aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cmake.conf2
-rw-r--r--.gitignore4
-rw-r--r--dependencies.yaml10
-rw-r--r--examples/platforms/android/doc/src/qml_in_android_studio_projects.qdoc133
-rw-r--r--examples/platforms/android/qml_in_android_view/CMakeLists.txt5
-rw-r--r--examples/platforms/android/qml_in_android_view/Main.qml (renamed from examples/platforms/android/qml_in_android_view/main.qml)5
-rw-r--r--examples/platforms/android/qml_in_android_view/Second.qml78
-rw-r--r--examples/platforms/android/qml_in_java_based_android_project/app/build.gradle2
-rw-r--r--examples/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java158
-rw-r--r--examples/platforms/android/qml_in_java_based_android_project/app/src/main/res/layout/activity_main.xml45
-rw-r--r--examples/platforms/android/qml_in_kotlin_based_android_project/app/build.gradle2
-rw-r--r--examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt112
-rw-r--r--examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/res/layout/activity_main.xml36
-rw-r--r--examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/res/values/strings.xml3
-rw-r--r--examples/quick/quickshapes/shapes/CMakeLists.txt3
-rw-r--r--examples/quick/quickshapes/shapes/fillItem.qml50
-rw-r--r--examples/quick/quickshapes/shapes/fillTransform.qml46
-rw-r--r--examples/quick/quickshapes/shapes/rectangle.qml57
-rw-r--r--examples/quick/quickshapes/shapes/shapegallery.qml12
-rw-r--r--examples/quick/quickshapes/shapes/shapes.qrc2
-rw-r--r--examples/quick/scenegraph/graph/shaders/noisy.frag2
-rw-r--r--examples/quick/scenegraph/graph/shaders/noisy.frag.qsbbin1763 -> 1760 bytes
-rw-r--r--examples/quick/scenegraph/graph/shaders/noisy.vert4
-rw-r--r--examples/quick/scenegraph/graph/shaders/noisy.vert.qsbbin1650 -> 1646 bytes
-rw-r--r--examples/quick/scenegraph/openglunderqml/squircle.cpp30
-rw-r--r--examples/quick/scenegraph/openglunderqml/squircle.h2
-rw-r--r--examples/quickcontrols/spreadsheets/CMakeLists.txt46
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/CMakeLists.txt47
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/HeaderToolBar.qml96
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/HelpDialog.qml111
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/Main.qml846
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/TableCell.qml41
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/datamodel.cpp266
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/datamodel.h63
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/copy.svg6
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/cut.svg6
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/help.svg5
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/hide.svg4
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_column_left.svg3
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_column_right.svg3
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_row_above.svg3
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_row_below.svg3
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/pan.svg4
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/paste.svg6
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/remove_column.svg3
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/remove_row.svg3
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/reset_reordering.svg3
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/icons/show.svg3
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/spreadcell.cpp69
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/spreadcell.h26
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/spreadformula.cpp74
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/spreadformula.h43
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/spreadkey.h23
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/spreadmimedataprovider.cpp88
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/spreadmimedataprovider.h39
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/spreadmodel.cpp730
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/spreadmodel.h154
-rw-r--r--examples/quickcontrols/spreadsheets/Spreadsheets/spreadrole.h23
-rw-r--r--examples/quickcontrols/spreadsheets/main.cpp24
-rw-r--r--examples/quickcontrols/spreadsheets/spreadsheet.svg32
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/doc/qtqmlcore.qdocconf10
-rw-r--r--src/core/doc/src/qmlpermissions.qdoc2
-rw-r--r--src/core/doc/src/qtqmlcore-qmltypes.qdoc6
-rw-r--r--src/core/doc/src/qtqmlcore.qdoc4
-rw-r--r--src/core/qqmlsettings.cpp2
-rw-r--r--src/effects/CMakeLists.txt1
-rw-r--r--src/effects/qquickmultieffect.cpp2
-rw-r--r--src/imports/tooling/Method.qml2
-rw-r--r--src/imports/tooling/Parameter.qml2
-rw-r--r--src/imports/tooling/Property.qml3
-rw-r--r--src/labs/animation/CMakeLists.txt1
-rw-r--r--src/labs/animation/qquickboundaryrule.cpp2
-rw-r--r--src/labs/folderlistmodel/CMakeLists.txt1
-rw-r--r--src/labs/folderlistmodel/fileinfothread.cpp2
-rw-r--r--src/labs/folderlistmodel/qquickfolderlistmodel.cpp2
-rw-r--r--src/labs/models/CMakeLists.txt1
-rw-r--r--src/labs/models/qqmltablemodel.cpp2
-rw-r--r--src/labs/platform/qquicklabsplatformdialog.cpp2
-rw-r--r--src/labs/platform/qquicklabsplatformmenu_p.h3
-rw-r--r--src/labs/platform/qquicklabsplatformmenubar.cpp2
-rw-r--r--src/labs/platform/qquicklabsplatformsystemtrayicon.cpp2
-rw-r--r--src/labs/settings/CMakeLists.txt1
-rw-r--r--src/labs/settings/qqmlsettings.cpp6
-rw-r--r--src/labs/sharedimage/CMakeLists.txt1
-rw-r--r--src/labs/wavefrontmesh/CMakeLists.txt1
-rw-r--r--src/particles/CMakeLists.txt1
-rw-r--r--src/plugins/qmllint/quick/CMakeLists.txt2
-rw-r--r--src/plugins/qmllint/quick/qquickliteralbindingcheck.cpp17
-rw-r--r--src/plugins/qmllint/quick/qquickliteralbindingcheck_p.h38
-rw-r--r--src/plugins/qmllint/quick/qquickvaluetypefromstringcheck.cpp81
-rw-r--r--src/plugins/qmllint/quick/qquickvaluetypefromstringcheck_p.h32
-rw-r--r--src/plugins/qmllint/quick/quicklintplugin.cpp5
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp3
-rw-r--r--src/qml/CMakeLists.txt195
-rw-r--r--src/qml/Qt6AndroidQmlMacros.cmake8
-rw-r--r--src/qml/Qt6QmlDeploySupport.cmake11
-rw-r--r--src/qml/Qt6QmlMacros.cmake437
-rw-r--r--src/qml/Qt6qt.conf.in5
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h4
-rw-r--r--src/qml/common/qv4alloca_p.h36
-rw-r--r--src/qml/common/qv4compileddata_p.h6
-rw-r--r--src/qml/common/qv4staticvalue_p.h4
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp13
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h1
-rw-r--r--src/qml/compiler/qv4codegen.cpp4
-rw-r--r--src/qml/doc/qtqml.qdocconf20
-rw-r--r--src/qml/doc/snippets/qml/function-call-binding.qml18
-rw-r--r--src/qml/doc/src/cmake/cmake-properties.qdoc21
-rw-r--r--src/qml/doc/src/cmake/policy/qtp0005.qdoc42
-rw-r--r--src/qml/doc/src/cmake/qt_add_qml_module.qdoc3
-rw-r--r--src/qml/doc/src/cmake/qt_target_qml_sources.qdoc13
-rw-r--r--src/qml/doc/src/cppclasses/topic.qdoc6
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc2
-rw-r--r--src/qml/doc/src/external-resources.qdoc8
-rw-r--r--src/qml/doc/src/javascript/qmlglobalobject.qdoc4
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc4
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/structure.qdoc25
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc7
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc2
-rw-r--r--src/qml/doc/src/qmlsingletons.qdoc2
-rw-r--r--src/qml/doc/src/qmltypereference.qdoc4
-rw-r--r--src/qml/doc/src/qtqml-cpp.qdoc6
-rw-r--r--src/qml/doc/src/qtqml.qdoc16
-rw-r--r--src/qml/doc/src/tools/qtqml-tooling-qmllint.qdoc7
-rw-r--r--src/qml/jit/qv4assemblercommon.cpp2
-rw-r--r--src/qml/jit/qv4baselineassembler.cpp14
-rw-r--r--src/qml/jit/qv4baselinejit_p.h6
-rw-r--r--src/qml/jsapi/qjsprimitivevalue.h20
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp8
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h4
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp5
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp63
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4context.cpp4
-rw-r--r--src/qml/jsruntime/qv4context_p.h2
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp4
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h2
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp85
-rw-r--r--src/qml/jsruntime/qv4engine_p.h2
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp32
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h16
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit_p.h1
-rw-r--r--src/qml/jsruntime/qv4function.cpp20
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp246
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h210
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4generatorobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4globalobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4jscall_p.h7
-rw-r--r--src/qml/jsruntime/qv4managed_p.h2
-rw-r--r--src/qml/jsruntime/qv4mapobject.cpp28
-rw-r--r--src/qml/jsruntime/qv4mapobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4object.cpp8
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp4
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h2
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4promiseobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4proxy.cpp39
-rw-r--r--src/qml/jsruntime/qv4proxy_p.h17
-rw-r--r--src/qml/jsruntime/qv4qmetaobjectwrapper.cpp71
-rw-r--r--src/qml/jsruntime/qv4qmetaobjectwrapper_p.h72
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp2
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp127
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h11
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp77
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h6
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp136
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4setobject.cpp19
-rw-r--r--src/qml/jsruntime/qv4setobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4symbol.cpp4
-rw-r--r--src/qml/jsruntime/qv4symbol_p.h2
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp14
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h4
-rw-r--r--src/qml/jsruntime/qv4urlobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4urlobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4value_p.h5
-rw-r--r--src/qml/jsruntime/qv4vtable_p.h77
-rw-r--r--src/qml/memory/qv4mm.cpp6
-rw-r--r--src/qml/parser/qqmljslexer.cpp4
-rw-r--r--src/qml/parser/qqmljslexer_p.h2
-rw-r--r--src/qml/qml/ftw/qqmlnullablevalue_p.h2
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp2
-rw-r--r--src/qml/qml/qqml.cpp32
-rw-r--r--src/qml/qml/qqmlbinding.cpp3
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp5
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions.cpp77
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions_p.h19
-rw-r--r--src/qml/qml/qqmlcomponent.cpp2
-rw-r--r--src/qml/qml/qqmlcomponentandaliasresolver_p.h28
-rw-r--r--src/qml/qml/qqmlcontextdata_p.h4
-rw-r--r--src/qml/qml/qqmldatablob.cpp5
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp5
-rw-r--r--src/qml/qml/qqmlengine.cpp84
-rw-r--r--src/qml/qml/qqmlglobal.cpp8
-rw-r--r--src/qml/qml/qqmlglobal_p.h1
-rw-r--r--src/qml/qml/qqmlimport.cpp45
-rw-r--r--src/qml/qml/qqmlimport_p.h7
-rw-r--r--src/qml/qml/qqmlirloader.cpp2
-rw-r--r--src/qml/qml/qqmllocale_p.h23
-rw-r--r--src/qml/qml/qqmlloggingcategorybase_p.h47
-rw-r--r--src/qml/qml/qqmlmetamoduleregistration.cpp26
-rw-r--r--src/qml/qml/qqmlmetatype.cpp4
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp2
-rw-r--r--src/qml/qml/qqmlplatform.cpp7
-rw-r--r--src/qml/qml/qqmlplatform_p.h1
-rw-r--r--src/qml/qml/qqmlpluginimporter.cpp2
-rw-r--r--src/qml/qml/qqmlproperty.h1
-rw-r--r--src/qml/qml/qqmlpropertybinding.cpp2
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp20
-rw-r--r--src/qml/qml/qqmlpropertydata_p.h13
-rw-r--r--src/qml/qml/qqmlscriptblob.cpp5
-rw-r--r--src/qml/qml/qqmlscriptblob_p.h1
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp10
-rw-r--r--src/qml/qml/qqmltypedata.cpp8
-rw-r--r--src/qml/qml/qqmltypedata_p.h2
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp225
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h86
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h14
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp45
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h8
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp2
-rw-r--r--src/qml/qqmlbuiltins_p.h228
-rw-r--r--src/qml/types/qqmlbind.cpp6
-rw-r--r--src/qml/types/qqmlbind_p.h4
-rw-r--r--src/qml/types/qqmlconnections.cpp7
-rw-r--r--src/qml/types/qqmlconnections_p.h6
-rw-r--r--src/qml/types/qqmllocaleenums_p.h48
-rw-r--r--src/qml/types/qqmlloggingcategory.cpp (renamed from src/qml/qml/qqmlloggingcategory.cpp)15
-rw-r--r--src/qml/types/qqmlloggingcategory_p.h (renamed from src/qml/qml/qqmlloggingcategory_p.h)19
-rw-r--r--src/qml/types/qqmltimer_p.h8
-rw-r--r--src/qmlcompiler/CMakeLists.txt30
-rw-r--r--src/qmlcompiler/qdeferredpointer_p.h8
-rw-r--r--src/qmlcompiler/qqmljsbasicblocks.cpp4
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp259
-rw-r--r--src/qmlcompiler/qqmljscodegenerator_p.h28
-rw-r--r--src/qmlcompiler/qqmljscompilepass_p.h3
-rw-r--r--src/qmlcompiler/qqmljscompiler.cpp38
-rw-r--r--src/qmlcompiler/qqmljscompiler_p.h14
-rw-r--r--src/qmlcompiler/qqmljscompilerstats.cpp188
-rw-r--r--src/qmlcompiler/qqmljscompilerstats_p.h92
-rw-r--r--src/qmlcompiler/qqmljscompilerstatsreporter.cpp118
-rw-r--r--src/qmlcompiler/qqmljscompilerstatsreporter_p.h57
-rw-r--r--src/qmlcompiler/qqmljsfunctioninitializer.cpp4
-rw-r--r--src/qmlcompiler/qqmljsimporter.cpp38
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp1
-rw-r--r--src/qmlcompiler/qqmljslintercodegen.cpp7
-rw-r--r--src/qmlcompiler/qqmljsmetatypes_p.h10
-rw-r--r--src/qmlcompiler/qqmljsoptimizations.cpp44
-rw-r--r--src/qmlcompiler/qqmljsregistercontent.cpp161
-rw-r--r--src/qmlcompiler/qqmljsregistercontent_p.h94
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp21
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h13
-rw-r--r--src/qmlcompiler/qqmljsshadowcheck.cpp6
-rw-r--r--src/qmlcompiler/qqmljsstoragegeneralizer.cpp1
-rw-r--r--src/qmlcompiler/qqmljsstorageinitializer.cpp81
-rw-r--r--src/qmlcompiler/qqmljsstorageinitializer_p.h40
-rw-r--r--src/qmlcompiler/qqmljstypedescriptionreader.cpp21
-rw-r--r--src/qmlcompiler/qqmljstypepropagator.cpp168
-rw-r--r--src/qmlcompiler/qqmljstyperesolver.cpp448
-rw-r--r--src/qmlcompiler/qqmljstyperesolver_p.h32
-rw-r--r--src/qmlcompiler/qqmljsutils.cpp5
-rw-r--r--src/qmlcompiler/qqmljsutils_p.h13
-rw-r--r--src/qmldom/qqmldomastcreator.cpp479
-rw-r--r--src/qmldom/qqmldomastcreator_p.h53
-rw-r--r--src/qmldom/qqmldomcodeformatter.cpp2
-rw-r--r--src/qmldom/qqmldomcomments.cpp2
-rw-r--r--src/qmldom/qqmldomconstants_p.h3
-rw-r--r--src/qmldom/qqmldomelements.cpp15
-rw-r--r--src/qmldom/qqmldomelements_p.h11
-rw-r--r--src/qmldom/qqmldomexternalitems_p.h5
-rw-r--r--src/qmldom/qqmldomitem.cpp2
-rw-r--r--src/qmldom/qqmldomitem_p.h2
-rw-r--r--src/qmldom/qqmldomoutwriter.cpp3
-rw-r--r--src/qmldom/qqmldomreformatter.cpp13
-rw-r--r--src/qmldom/qqmldomreformatter_p.h1
-rw-r--r--src/qmldom/qqmldomscriptelements.cpp3
-rw-r--r--src/qmldom/qqmldomscriptelements_p.h20
-rw-r--r--src/qmldom/qqmldomtop.cpp123
-rw-r--r--src/qmldom/qqmldomtop_p.h9
-rw-r--r--src/qmlintegration/qqmlintegration.h4
-rw-r--r--src/qmllocalstorage/CMakeLists.txt1
-rw-r--r--src/qmlls/CMakeLists.txt3
-rw-r--r--src/qmlls/qdochtmlparser.cpp119
-rw-r--r--src/qmlls/qdochtmlparser_p.h30
-rw-r--r--src/qmlls/qlanguageserver.cpp14
-rw-r--r--src/qmlls/qlanguageserver_p.h3
-rw-r--r--src/qmlls/qqmlbasemodule_p.h26
-rw-r--r--src/qmlls/qqmlcodemodel.cpp23
-rw-r--r--src/qmlls/qqmlcodemodel_p.h11
-rw-r--r--src/qmlls/qqmlcompletionsupport.cpp11
-rw-r--r--src/qmlls/qqmlcompletionsupport_p.h3
-rw-r--r--src/qmlls/qqmlfindusagessupport.cpp6
-rw-r--r--src/qmlls/qqmlformatting.cpp6
-rw-r--r--src/qmlls/qqmlformatting_p.h2
-rw-r--r--src/qmlls/qqmlgotodefinitionsupport.cpp2
-rw-r--r--src/qmlls/qqmlgototypedefinitionsupport.cpp2
-rw-r--r--src/qmlls/qqmlhighlightsupport.cpp30
-rw-r--r--src/qmlls/qqmlhover.cpp55
-rw-r--r--src/qmlls/qqmlhover_p.h6
-rw-r--r--src/qmlls/qqmllintsuggestions.cpp7
-rw-r--r--src/qmlls/qqmllscompletion.cpp23
-rw-r--r--src/qmlls/qqmllscompletion_p.h6
-rw-r--r--src/qmlls/qqmllshelpplugininterface.cpp4
-rw-r--r--src/qmlls/qqmllshelpplugininterface_p.h64
-rw-r--r--src/qmlls/qqmllshelputils.cpp255
-rw-r--r--src/qmlls/qqmllshelputils_p.h59
-rw-r--r--src/qmlls/qqmllsutils.cpp645
-rw-r--r--src/qmlls/qqmllsutils_p.h220
-rw-r--r--src/qmlls/qqmlrangeformatting.cpp2
-rw-r--r--src/qmlls/qqmlrenamesymbolsupport.cpp19
-rw-r--r--src/qmlls/qqmlsemantictokens.cpp44
-rw-r--r--src/qmlls/qqmlsemantictokens_p.h3
-rw-r--r--src/qmlmodels/CMakeLists.txt3
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp46
-rw-r--r--src/qmlmodels/qqmldmabstractitemmodeldata_p.h11
-rw-r--r--src/qmlnetwork/CMakeLists.txt1
-rw-r--r--src/qmlnetwork/doc/src/qtqmlnetwork-qmltypes.qdoc2
-rw-r--r--src/qmltest/CMakeLists.txt1
-rw-r--r--src/qmltest/doc/snippets/testApp/CMakeLists.txt2
-rw-r--r--src/qmltest/doc/snippets/testApp/MyModule/CMakeLists.txt2
-rw-r--r--src/qmltest/doc/snippets/testApp/tests/CMakeLists.txt2
-rw-r--r--src/qmltest/doc/snippets/testApp/tests/main.cpp2
-rw-r--r--src/qmltest/doc/snippets/testApp/tests/setup.cpp2
-rw-r--r--src/qmltest/doc/snippets/testApp/tests/setup.h2
-rw-r--r--src/qmltest/quicktest.cpp12
-rw-r--r--src/qmltoolingsettings/CMakeLists.txt1
-rw-r--r--src/qmltoolingsettings/qqmltoolingsettings.cpp4
-rw-r--r--src/qmltoolingsettings/qqmltoolingsettings_p.h4
-rw-r--r--src/qmltyperegistrar/CMakeLists.txt1
-rw-r--r--src/qmltyperegistrar/jsroot_metatypes.json22
-rw-r--r--src/qmltyperegistrar/qmetatypesjsonprocessor.cpp46
-rw-r--r--src/qmltyperegistrar/qmetatypesjsonprocessor_p.h29
-rw-r--r--src/qmltyperegistrar/qqmltyperegistrar.cpp38
-rw-r--r--src/qmltyperegistrar/qqmltyperegistrar_p.h2
-rw-r--r--src/qmltyperegistrar/qqmltyperegistrarconstants_p.h4
-rw-r--r--src/qmltyperegistrar/qqmltypesclassdescription.cpp97
-rw-r--r--src/qmltyperegistrar/qqmltypesclassdescription_p.h8
-rw-r--r--src/qmltyperegistrar/qqmltypescreator.cpp10
-rw-r--r--src/qmltyperegistrar/qqmltypescreator_p.h2
-rw-r--r--src/qmlworkerscript/CMakeLists.txt3
-rw-r--r--src/qmlxmllistmodel/CMakeLists.txt1
-rw-r--r--src/quick/CMakeLists.txt48
-rw-r--r--src/quick/accessible/qaccessiblequickitem.cpp27
-rw-r--r--src/quick/doc/snippets/pointerHandlers/dragHandlerAcceptedButtons.qml81
-rw-r--r--src/quick/doc/snippets/pointerHandlers/dragHandlerMargin.qml27
-rw-r--r--src/quick/doc/snippets/pointerHandlers/draggableGridView.qml121
-rw-r--r--src/quick/doc/snippets/pointerHandlers/pinchHandlerSimple.qml (renamed from src/quick/doc/snippets/pointerHandlers/pinchHandler.qml)5
-rw-r--r--src/quick/doc/snippets/qml/font.qml22
-rw-r--r--src/quick/doc/snippets/qml/tableview/editdelegate.qml2
-rw-r--r--src/quick/doc/snippets/qml/windowPalette.qml2
-rw-r--r--src/quick/doc/snippets/qquickrhiitem/qquickrhiitem_intro.frag10
-rw-r--r--src/quick/doc/snippets/qquickrhiitem/qquickrhiitem_intro.vert15
-rw-r--r--src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc9
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc16
-rw-r--r--src/quick/doc/src/qtquick.qdoc7
-rw-r--r--src/quick/handlers/qquickdragaxis.cpp2
-rw-r--r--src/quick/handlers/qquickdraghandler.cpp89
-rw-r--r--src/quick/handlers/qquickhandlerpoint.cpp1
-rw-r--r--src/quick/handlers/qquickhoverhandler.cpp2
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp4
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp5
-rw-r--r--src/quick/handlers/qquickpointerhandler_p.h1
-rw-r--r--src/quick/handlers/qquicksinglepointhandler.cpp3
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp5
-rw-r--r--src/quick/handlers/qquickwheelhandler.cpp2
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp2
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp109
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h42
-rw-r--r--src/quick/items/qquickborderimage.cpp26
-rw-r--r--src/quick/items/qquickflickable.cpp12
-rw-r--r--src/quick/items/qquickflickable_p_p.h50
-rw-r--r--src/quick/items/qquickimage.cpp79
-rw-r--r--src/quick/items/qquickimagebase.cpp87
-rw-r--r--src/quick/items/qquickimagebase_p.h5
-rw-r--r--src/quick/items/qquickimagebase_p_p.h11
-rw-r--r--src/quick/items/qquickitem.cpp11
-rw-r--r--src/quick/items/qquickitem_p.h5
-rw-r--r--src/quick/items/qquickitemsmodule.cpp4
-rw-r--r--src/quick/items/qquickitemview.cpp20
-rw-r--r--src/quick/items/qquickitemview_p_p.h5
-rw-r--r--src/quick/items/qquicklistview.cpp7
-rw-r--r--src/quick/items/qquickloader.cpp2
-rw-r--r--src/quick/items/qquickmousearea.cpp2
-rw-r--r--src/quick/items/qquickpalettecolorprovider.cpp1
-rw-r--r--src/quick/items/qquickpathview.cpp30
-rw-r--r--src/quick/items/qquickpathview_p_p.h5
-rw-r--r--src/quick/items/qquickpincharea.cpp2
-rw-r--r--src/quick/items/qquickrendertarget.cpp5
-rw-r--r--src/quick/items/qquickrhiitem.cpp66
-rw-r--r--src/quick/items/qquickselectable_p.h2
-rw-r--r--src/quick/items/qquickstateoperations.cpp24
-rw-r--r--src/quick/items/qquicktableview.cpp714
-rw-r--r--src/quick/items/qquicktableview_p.h8
-rw-r--r--src/quick/items/qquicktableview_p_p.h119
-rw-r--r--src/quick/items/qquicktext.cpp31
-rw-r--r--src/quick/items/qquicktextcontrol.cpp43
-rw-r--r--src/quick/items/qquicktextdocument.cpp26
-rw-r--r--src/quick/items/qquicktextedit.cpp21
-rw-r--r--src/quick/items/qquicktextinput.cpp11
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp3
-rw-r--r--src/quick/items/qquickwindow.cpp111
-rw-r--r--src/quick/items/qquickwindow_p.h2
-rw-r--r--src/quick/items/qquickwindowcontainer.cpp40
-rw-r--r--src/quick/items/qquickwindowmodule.cpp6
-rw-r--r--src/quick/items/qquickwindowmodule_p.h8
-rw-r--r--src/quick/items/qsginternaltextnode.cpp2
-rw-r--r--src/quick/jar/CMakeLists.txt11
-rw-r--r--src/quick/jar/build.gradle51
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtAbstractItemModel.java105
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtAbstractItemModelProxy.java35
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtAbstractListModel.java30
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtModelIndex.java42
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQmlComponent.java206
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQmlStatus.java49
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQmlStatusChangeListener.java17
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQuickView.java188
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc38
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtSignalListener.java17
-rw-r--r--src/quick/jar/settings.gradle1
-rw-r--r--src/quick/platform/android/qandroiditemmodelproxy.cpp379
-rw-r--r--src/quick/platform/android/qandroiditemmodelproxy_p.h191
-rw-r--r--src/quick/platform/android/qandroidmodelindexproxy.cpp103
-rw-r--r--src/quick/platform/android/qandroidmodelindexproxy_p.h56
-rw-r--r--src/quick/platform/android/qandroidquickviewembedding.cpp321
-rw-r--r--src/quick/platform/android/qandroidquickviewembedding_p.h42
-rw-r--r--src/quick/platform/android/qandroidtypeconverter_p.h99
-rw-r--r--src/quick/platform/android/qandroidtypes_p.h43
-rw-r--r--src/quick/platform/android/qandroidviewsignalmanager.cpp77
-rw-r--r--src/quick/platform/android/qandroidviewsignalmanager_p.h57
-rw-r--r--src/quick/qtquickglobal_p.h1
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp2
-rw-r--r--src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp10
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp11
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialshader.cpp23
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialshader.h11
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture.cpp6
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp7
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h2
-rw-r--r--src/quick/scenegraph/qsgcontextplugin.cpp2
-rw-r--r--src/quick/scenegraph/qsgcurvefillnode.cpp1
-rw-r--r--src/quick/scenegraph/qsgcurvefillnode_p.cpp157
-rw-r--r--src/quick/scenegraph/qsgcurvefillnode_p.h101
-rw-r--r--src/quick/scenegraph/qsgcurvefillnode_p_p.h13
-rw-r--r--src/quick/scenegraph/qsgcurveprocessor.cpp4
-rw-r--r--src/quick/scenegraph/qsgcurveprocessor_p.h4
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.h2
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp30
-rw-r--r--src/quick/scenegraph/shaders_ng/shapecurve.frag12
-rw-r--r--src/quick/scenegraph/shaders_ng/shapecurve.vert17
-rw-r--r--src/quick/scenegraph/util/qquadpath.cpp5
-rw-r--r--src/quick/scenegraph/util/qsgtransform.cpp10
-rw-r--r--src/quick/scenegraph/util/qsgtransform_p.h105
-rw-r--r--src/quick/util/qminimalflatset_p.h149
-rw-r--r--src/quick/util/qquickanimation.cpp5
-rw-r--r--src/quick/util/qquickdeliveryagent.cpp55
-rw-r--r--src/quick/util/qquickdeliveryagent_p.h4
-rw-r--r--src/quick/util/qquickdeliveryagent_p_p.h1
-rw-r--r--src/quick/util/qquickpath.cpp291
-rw-r--r--src/quick/util/qquickpath_p.h78
-rw-r--r--src/quick/util/qquickpixmapcache.cpp23
-rw-r--r--src/quick/util/qquickprofiler_p.h8
-rw-r--r--src/quick/util/qquicksmoothedanimation_p_p.h2
-rw-r--r--src/quick/util/qquickstate_p.h2
-rw-r--r--src/quick/util/qquickstategroup.cpp2
-rw-r--r--src/quick/util/qquickstyledtext.cpp2
-rw-r--r--src/quick/util/qquicktimeline.cpp2
-rw-r--r--src/quick/util/qquicktransitionmanager.cpp2
-rw-r--r--src/quick/util/qquickvaluetypes.cpp186
-rw-r--r--src/quick/util/qquickvaluetypes_p.h34
-rw-r--r--src/quickcontrols/CMakeLists.txt6
-rw-r--r--src/quickcontrols/basic/CMakeLists.txt1
-rw-r--r--src/quickcontrols/basic/ComboBox.qml4
-rw-r--r--src/quickcontrols/basic/Dialog.qml2
-rw-r--r--src/quickcontrols/basic/Tumbler.qml9
-rw-r--r--src/quickcontrols/configure.cmake8
-rw-r--r--src/quickcontrols/doc/images/qtquickcontrols-menu-native.pngbin0 -> 7479 bytes
-rw-r--r--src/quickcontrols/doc/images/qtquickcontrols-menu.pngbin3629 -> 12317 bytes
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-busyindicator-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-button-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-checkbox-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-checkdelegate-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-combobox-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-delaybutton-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-dial-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-frame-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-groupbox-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-headerview.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate.qml3
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-label-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-menu-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-menubar-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-menuseparator-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-pageindicator-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-pane-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-popup-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-progressbar-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-radiobutton-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-radiodelegate-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-rangeslider-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-scrollbar-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-scrollindicator-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-scrollview-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-slider-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-spinbox-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-splitview-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-stackview-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-swipedelegate-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-swipeview-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-switch-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-switchdelegate-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-tabbar-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-textarea-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-textfield-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-toolbar-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-toolbutton-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-toolseparator-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-custom.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-pressandhold.qml2
-rw-r--r--src/quickcontrols/doc/snippets/qtquickcontrols-tumbler-custom.qml2
-rw-r--r--src/quickcontrols/doc/src/includes/qquickheaderview.qdocinc18
-rw-r--r--src/quickcontrols/doc/src/includes/qquickmenu.qdocinc4
-rw-r--r--src/quickcontrols/doc/src/qtquickcontrols-customize.qdoc10
-rw-r--r--src/quickcontrols/doc/src/qtquickcontrols-fusion.qdoc15
-rw-r--r--src/quickcontrols/doc/src/qtquickcontrols-styles.qdoc22
-rw-r--r--src/quickcontrols/fluentwinui3/ApplicationWindow.qml12
-rw-r--r--src/quickcontrols/fluentwinui3/Button.qml59
-rw-r--r--src/quickcontrols/fluentwinui3/CMakeLists.txt79
-rw-r--r--src/quickcontrols/fluentwinui3/CheckBox.qml61
-rw-r--r--src/quickcontrols/fluentwinui3/ComboBox.qml138
-rw-r--r--src/quickcontrols/fluentwinui3/Config.qml20664
-rw-r--r--src/quickcontrols/fluentwinui3/Frame.qml34
-rw-r--r--src/quickcontrols/fluentwinui3/GroupBox.qml64
-rw-r--r--src/quickcontrols/fluentwinui3/ItemDelegate.qml87
-rw-r--r--src/quickcontrols/fluentwinui3/Popup.qml52
-rw-r--r--src/quickcontrols/fluentwinui3/ProgressBar.qml117
-rw-r--r--src/quickcontrols/fluentwinui3/RadioButton.qml59
-rw-r--r--src/quickcontrols/fluentwinui3/RangeSlider.qml197
-rw-r--r--src/quickcontrols/fluentwinui3/Slider.qml144
-rw-r--r--src/quickcontrols/fluentwinui3/SpinBox.qml106
-rw-r--r--src/quickcontrols/fluentwinui3/StyleImage.qml54
-rw-r--r--src/quickcontrols/fluentwinui3/Switch.qml81
-rw-r--r--src/quickcontrols/fluentwinui3/TabBar.qml52
-rw-r--r--src/quickcontrols/fluentwinui3/TabButton.qml85
-rw-r--r--src/quickcontrols/fluentwinui3/TextArea.qml73
-rw-r--r--src/quickcontrols/fluentwinui3/TextField.qml73
-rw-r--r--src/quickcontrols/fluentwinui3/ToolBar.qml35
-rw-r--r--src/quickcontrols/fluentwinui3/ToolButton.qml57
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@2x.pngbin0 -> 270 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@3x.pngbin0 -> 355 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered.pngbin0 -> 381 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@2x.pngbin0 -> 775 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@3x.pngbin0 -> 1268 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed.pngbin0 -> 249 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@2x.pngbin0 -> 471 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@3x.pngbin0 -> 621 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked.pngbin0 -> 301 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked@2x.pngbin0 -> 790 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-checked@3x.pngbin0 -> 1261 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-disabled.pngbin0 -> 207 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@2x.pngbin0 -> 364 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@3x.pngbin0 -> 486 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-hovered.pngbin0 -> 310 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@2x.pngbin0 -> 592 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@3x.pngbin0 -> 1037 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-pressed.pngbin0 -> 206 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@2x.pngbin0 -> 364 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@3x.pngbin0 -> 494 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background.pngbin0 -> 302 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background@2x.pngbin0 -> 679 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/button-background@3x.pngbin0 -> 1170 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled.pngbin0 -> 237 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@2x.pngbin0 -> 351 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@3x.pngbin0 -> 452 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered.pngbin0 -> 270 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@2x.pngbin0 -> 389 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@3x.pngbin0 -> 511 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed.pngbin0 -> 270 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@2x.pngbin0 -> 420 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@3x.pngbin0 -> 530 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked.pngbin0 -> 234 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@2x.pngbin0 -> 360 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@3x.pngbin0 -> 455 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@2x.pngbin0 -> 260 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@3x.pngbin0 -> 328 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled.pngbin0 -> 201 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@2x.pngbin0 -> 286 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@3x.pngbin0 -> 393 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@2x.pngbin0 -> 298 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@3x.pngbin0 -> 388 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@2x.pngbin0 -> 289 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@3x.pngbin0 -> 409 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@2x.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@3x.pngbin0 -> 414 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked.pngbin0 -> 196 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@2x.pngbin0 -> 274 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@3x.pngbin0 -> 342 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed.pngbin0 -> 205 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@2x.pngbin0 -> 314 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@3x.pngbin0 -> 409 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@2x.pngbin0 -> 394 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@3x.pngbin0 -> 546 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-disabled.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-disabled@2x.pngbin0 -> 315 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-disabled@3x.pngbin0 -> 479 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-focused.pngbin0 -> 310 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-focused@2x.pngbin0 -> 687 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-focused@3x.pngbin0 -> 1146 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered-open.pngbin0 -> 309 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered-open@2x.pngbin0 -> 677 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered-open@3x.pngbin0 -> 1132 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered.pngbin0 -> 309 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered@2x.pngbin0 -> 677 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered@3x.pngbin0 -> 1132 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-open-pressed.pngbin0 -> 207 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-open-pressed@2x.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-open-pressed@3x.pngbin0 -> 489 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-open.pngbin0 -> 310 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-open@2x.pngbin0 -> 687 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-open@3x.pngbin0 -> 1146 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-pressed.pngbin0 -> 207 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-pressed@2x.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background-pressed@3x.pngbin0 -> 489 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background.pngbin0 -> 310 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background@2x.pngbin0 -> 687 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-background@3x.pngbin0 -> 1146 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-disabled.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-disabled@2x.pngbin0 -> 167 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-disabled@3x.pngbin0 -> 177 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-focused.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-focused@2x.pngbin0 -> 167 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-focused@3x.pngbin0 -> 177 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered-open.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered-open@2x.pngbin0 -> 167 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered-open@3x.pngbin0 -> 177 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered@2x.pngbin0 -> 167 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered@3x.pngbin0 -> 177 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open-pressed.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open-pressed@2x.pngbin0 -> 167 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open-pressed@3x.pngbin0 -> 177 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open@2x.pngbin0 -> 167 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open@3x.pngbin0 -> 177 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-pressed.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-pressed@2x.pngbin0 -> 167 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-pressed@3x.pngbin0 -> 177 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator@2x.pngbin0 -> 167 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/combobox-indicator@3x.pngbin0 -> 177 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-hovered-open.pngbin0 -> 356 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-hovered-open@2x.pngbin0 -> 745 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-hovered-open@3x.pngbin0 -> 1257 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open-pressed.pngbin0 -> 356 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open-pressed@2x.pngbin0 -> 745 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open-pressed@3x.pngbin0 -> 1257 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open.pngbin0 -> 356 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open@2x.pngbin0 -> 745 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open@3x.pngbin0 -> 1257 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-hovered-open.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-hovered-open@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-hovered-open@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open-pressed.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open-pressed@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open-pressed@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-hovered-open.pngbin0 -> 3947 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-hovered-open@2x.pngbin0 -> 7741 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-hovered-open@3x.pngbin0 -> 14818 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open-pressed.pngbin0 -> 3947 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open-pressed@2x.pngbin0 -> 7741 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open-pressed@3x.pngbin0 -> 14818 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open.pngbin0 -> 3947 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open@2x.pngbin0 -> 7741 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open@3x.pngbin0 -> 14818 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@2x.pngbin0 -> 271 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@3x.pngbin0 -> 354 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered.pngbin0 -> 338 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@2x.pngbin0 -> 872 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@3x.pngbin0 -> 1410 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed.pngbin0 -> 265 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@2x.pngbin0 -> 495 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@3x.pngbin0 -> 621 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked.pngbin0 -> 308 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@2x.pngbin0 -> 775 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@3x.pngbin0 -> 1269 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@2x.pngbin0 -> 105 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@3x.pngbin0 -> 111 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered.pngbin0 -> 172 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@2x.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@3x.pngbin0 -> 325 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed.pngbin0 -> 174 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@2x.pngbin0 -> 241 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@3x.pngbin0 -> 325 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/frame-background-disabled.pngbin0 -> 375 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/frame-background-disabled@2x.pngbin0 -> 645 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/frame-background-disabled@3x.pngbin0 -> 972 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/frame-background.pngbin0 -> 375 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/frame-background@2x.pngbin0 -> 645 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/frame-background@3x.pngbin0 -> 972 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-hovered.pngbin0 -> 179 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-hovered@2x.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-hovered@3x.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-pressed.pngbin0 -> 177 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-pressed@2x.pngbin0 -> 257 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-pressed@3x.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted.pngbin0 -> 177 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted@2x.pngbin0 -> 257 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted@3x.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-hovered.pngbin0 -> 177 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-hovered@2x.pngbin0 -> 257 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-hovered@3x.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-pressed.pngbin0 -> 179 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-pressed@2x.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-pressed@3x.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/popup-background.pngbin0 -> 6626 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/popup-background@2x.pngbin0 -> 15844 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/popup-background@3x.pngbin0 -> 38877 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled.pngbin0 -> 82 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@2x.pngbin0 -> 99 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@3x.pngbin0 -> 111 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove.pngbin0 -> 82 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@2x.pngbin0 -> 98 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@3x.pngbin0 -> 111 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled.pngbin0 -> 348 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@2x.pngbin0 -> 545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@3x.pngbin0 -> 700 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@2x.pngbin0 -> 1198 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@3x.pngbin0 -> 1675 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed.pngbin0 -> 565 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@2x.pngbin0 -> 1044 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@3x.pngbin0 -> 1476 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked.pngbin0 -> 449 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@2x.pngbin0 -> 809 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@3x.pngbin0 -> 1109 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled.pngbin0 -> 334 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@2x.pngbin0 -> 516 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@3x.pngbin0 -> 691 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered.pngbin0 -> 395 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@2x.pngbin0 -> 600 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@3x.pngbin0 -> 792 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed.pngbin0 -> 485 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@2x.pngbin0 -> 815 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@3x.pngbin0 -> 1057 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator.pngbin0 -> 468 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@2x.pngbin0 -> 713 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@3x.pngbin0 -> 924 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@2x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@3x.pngbin0 -> 935 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@2x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@3x.pngbin0 -> 935 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@2x.pngbin0 -> 875 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@3x.pngbin0 -> 1283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@2x.pngbin0 -> 875 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@3x.pngbin0 -> 1283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@3x.pngbin0 -> 216 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@2x.pngbin0 -> 183 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@2x.pngbin0 -> 183 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@2x.pngbin0 -> 183 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@2x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@3x.pngbin0 -> 935 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@2x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@3x.pngbin0 -> 935 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@2x.pngbin0 -> 875 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@3x.pngbin0 -> 1283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@2x.pngbin0 -> 875 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@3x.pngbin0 -> 1283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@2x.pngbin0 -> 172 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@3x.pngbin0 -> 217 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered.pngbin0 -> 130 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@2x.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@3x.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed.pngbin0 -> 130 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@2x.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@3x.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove.pngbin0 -> 130 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove@2x.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-groove@3x.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@2x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@3x.pngbin0 -> 935 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@2x.pngbin0 -> 875 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@3x.pngbin0 -> 1283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@2x.pngbin0 -> 698 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@3x.pngbin0 -> 935 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle.pngbin0 -> 493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle@2x.pngbin0 -> 875 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/slider-handle@3x.pngbin0 -> 1283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-atlimit.pngbin0 -> 317 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-atlimit@2x.pngbin0 -> 683 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-atlimit@3x.pngbin0 -> 1138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-disabled.pngbin0 -> 196 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-disabled@2x.pngbin0 -> 312 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-disabled@3x.pngbin0 -> 470 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-hovered.pngbin0 -> 317 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-hovered@2x.pngbin0 -> 683 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-hovered@3x.pngbin0 -> 1138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-pressed.pngbin0 -> 317 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-pressed@2x.pngbin0 -> 683 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-pressed@3x.pngbin0 -> 1138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-hovered.pngbin0 -> 314 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-hovered@2x.pngbin0 -> 670 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-hovered@3x.pngbin0 -> 1120 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-hovered.pngbin0 -> 317 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-hovered@2x.pngbin0 -> 683 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-hovered@3x.pngbin0 -> 1138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-pressed.pngbin0 -> 317 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-pressed@2x.pngbin0 -> 683 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-pressed@3x.pngbin0 -> 1138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background.pngbin0 -> 317 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background@2x.pngbin0 -> 683 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-background@3x.pngbin0 -> 1138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-atlimit.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-atlimit@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-atlimit@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-disabled.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-disabled@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-disabled@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-hovered.pngbin0 -> 166 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-hovered@2x.pngbin0 -> 233 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-hovered@3x.pngbin0 -> 305 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-pressed.pngbin0 -> 166 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-pressed@2x.pngbin0 -> 233 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-pressed@3x.pngbin0 -> 305 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-hovered.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-hovered@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-hovered@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-hovered.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-hovered@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-hovered@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-pressed.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-pressed@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-pressed@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-atlimit.pngbin0 -> 145 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-atlimit@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-atlimit@3x.pngbin0 -> 211 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-disabled.pngbin0 -> 145 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-disabled@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-disabled@3x.pngbin0 -> 211 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-hovered.pngbin0 -> 118 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-hovered@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-hovered@3x.pngbin0 -> 211 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-pressed.pngbin0 -> 145 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-pressed@2x.pngbin0 -> 173 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-pressed@3x.pngbin0 -> 219 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-hovered.pngbin0 -> 118 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-hovered@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-hovered@3x.pngbin0 -> 211 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-hovered.pngbin0 -> 118 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-hovered@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-hovered@3x.pngbin0 -> 211 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-pressed.pngbin0 -> 118 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-pressed@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-pressed@3x.pngbin0 -> 211 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon.pngbin0 -> 118 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon@3x.pngbin0 -> 211 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-atlimit.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-atlimit@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-atlimit@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-disabled.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-disabled@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-disabled@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-hovered.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-hovered@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-hovered@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-pressed.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-pressed@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-pressed@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-hovered.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-hovered@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-hovered@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-hovered.pngbin0 -> 166 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-hovered@2x.pngbin0 -> 233 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-hovered@3x.pngbin0 -> 305 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-pressed.pngbin0 -> 166 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-pressed@2x.pngbin0 -> 233 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-pressed@3x.pngbin0 -> 305 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-atlimit.pngbin0 -> 133 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-atlimit@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-atlimit@3x.pngbin0 -> 210 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-disabled.pngbin0 -> 133 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-disabled@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-disabled@3x.pngbin0 -> 210 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-hovered.pngbin0 -> 118 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-hovered@2x.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-hovered@3x.pngbin0 -> 210 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-pressed.pngbin0 -> 118 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-pressed@2x.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-pressed@3x.pngbin0 -> 210 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-hovered.pngbin0 -> 118 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-hovered@2x.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-hovered@3x.pngbin0 -> 210 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-hovered.pngbin0 -> 118 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-hovered@2x.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-hovered@3x.pngbin0 -> 210 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-pressed.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-pressed@2x.pngbin0 -> 167 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-pressed@3x.pngbin0 -> 214 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon.pngbin0 -> 118 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon@2x.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon@3x.pngbin0 -> 210 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled.pngbin0 -> 270 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@2x.pngbin0 -> 390 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@3x.pngbin0 -> 508 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered.pngbin0 -> 317 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@2x.pngbin0 -> 470 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@3x.pngbin0 -> 605 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed.pngbin0 -> 326 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@2x.pngbin0 -> 489 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@3x.pngbin0 -> 628 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@2x.pngbin0 -> 416 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@3x.pngbin0 -> 542 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@2x.pngbin0 -> 530 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@3x.pngbin0 -> 702 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered.pngbin0 -> 376 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@2x.pngbin0 -> 620 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@3x.pngbin0 -> 795 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed.pngbin0 -> 371 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@2x.pngbin0 -> 592 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@3x.pngbin0 -> 774 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background.pngbin0 -> 515 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@2x.pngbin0 -> 810 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@3x.pngbin0 -> 1036 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled.pngbin0 -> 281 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@2x.pngbin0 -> 555 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@3x.pngbin0 -> 806 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered.pngbin0 -> 380 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@2x.pngbin0 -> 696 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@3x.pngbin0 -> 1021 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed.pngbin0 -> 384 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@2x.pngbin0 -> 710 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@3x.pngbin0 -> 1058 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked.pngbin0 -> 333 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@2x.pngbin0 -> 610 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@3x.pngbin0 -> 919 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled.pngbin0 -> 204 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@2x.pngbin0 -> 282 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@3x.pngbin0 -> 369 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@2x.pngbin0 -> 299 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@3x.pngbin0 -> 391 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@2x.pngbin0 -> 303 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@3x.pngbin0 -> 396 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle@2x.pngbin0 -> 274 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/switch-handle@3x.pngbin0 -> 349 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled.pngbin0 -> 417 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@2x.pngbin0 -> 977 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@3x.pngbin0 -> 1557 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused.pngbin0 -> 460 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@2x.pngbin0 -> 1106 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@3x.pngbin0 -> 1742 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered.pngbin0 -> 417 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@2x.pngbin0 -> 977 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@3x.pngbin0 -> 1557 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background.pngbin0 -> 417 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background@2x.pngbin0 -> 977 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textarea-background@3x.pngbin0 -> 1557 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled.pngbin0 -> 362 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@2x.pngbin0 -> 797 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@3x.pngbin0 -> 1215 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused.pngbin0 -> 310 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@2x.pngbin0 -> 728 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@3x.pngbin0 -> 1068 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered.pngbin0 -> 336 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@2x.pngbin0 -> 771 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@3x.pngbin0 -> 1121 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background.pngbin0 -> 348 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background@2x.pngbin0 -> 793 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/textfield-background@3x.pngbin0 -> 1191 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-disabled.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-disabled@2x.pngbin0 -> 268 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-disabled@3x.pngbin0 -> 345 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-hovered.pngbin0 -> 342 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-hovered@2x.pngbin0 -> 835 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-hovered@3x.pngbin0 -> 1366 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-pressed.pngbin0 -> 262 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-pressed@2x.pngbin0 -> 489 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-pressed@3x.pngbin0 -> 633 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked.pngbin0 -> 291 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked@2x.pngbin0 -> 747 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked@3x.pngbin0 -> 1223 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-disabled.pngbin0 -> 89 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-disabled@2x.pngbin0 -> 103 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-disabled@3x.pngbin0 -> 110 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-hovered.pngbin0 -> 173 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-hovered@2x.pngbin0 -> 249 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-hovered@3x.pngbin0 -> 325 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-pressed.pngbin0 -> 175 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-pressed@2x.pngbin0 -> 236 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-pressed@3x.pngbin0 -> 309 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/impl/CMakeLists.txt28
-rw-r--r--src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke.cpp52
-rw-r--r--src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke_p.h39
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@2x.pngbin0 -> 294 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@3x.pngbin0 -> 354 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered.pngbin0 -> 406 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@2x.pngbin0 -> 1099 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@3x.pngbin0 -> 1816 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@2x.pngbin0 -> 496 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@3x.pngbin0 -> 705 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked.pngbin0 -> 432 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked@2x.pngbin0 -> 1026 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-checked@3x.pngbin0 -> 1780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-disabled.pngbin0 -> 223 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-disabled@2x.pngbin0 -> 414 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-disabled@3x.pngbin0 -> 551 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-hovered.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-hovered@2x.pngbin0 -> 912 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-hovered@3x.pngbin0 -> 1369 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-pressed.pngbin0 -> 223 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-pressed@2x.pngbin0 -> 414 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background-pressed@3x.pngbin0 -> 551 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background.pngbin0 -> 386 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background@2x.pngbin0 -> 852 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/button-background@3x.pngbin0 -> 1596 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@2x.pngbin0 -> 355 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@3x.pngbin0 -> 455 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered.pngbin0 -> 261 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@2x.pngbin0 -> 382 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@3x.pngbin0 -> 506 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed.pngbin0 -> 259 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@2x.pngbin0 -> 412 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@3x.pngbin0 -> 514 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked.pngbin0 -> 248 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@2x.pngbin0 -> 368 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@3x.pngbin0 -> 460 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@2x.pngbin0 -> 262 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@3x.pngbin0 -> 331 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled.pngbin0 -> 201 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@2x.pngbin0 -> 295 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@3x.pngbin0 -> 395 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked.pngbin0 -> 207 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@2x.pngbin0 -> 298 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@3x.pngbin0 -> 395 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered.pngbin0 -> 209 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@2x.pngbin0 -> 310 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@3x.pngbin0 -> 430 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed.pngbin0 -> 211 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@2x.pngbin0 -> 327 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@3x.pngbin0 -> 396 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked.pngbin0 -> 198 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@2x.pngbin0 -> 282 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@3x.pngbin0 -> 351 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed.pngbin0 -> 205 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@2x.pngbin0 -> 323 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@3x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator.pngbin0 -> 205 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@2x.pngbin0 -> 325 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@3x.pngbin0 -> 448 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-disabled.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-disabled@2x.pngbin0 -> 417 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-disabled@3x.pngbin0 -> 628 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-focused.pngbin0 -> 450 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-focused@2x.pngbin0 -> 1004 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-focused@3x.pngbin0 -> 1677 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered-open.pngbin0 -> 432 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered-open@2x.pngbin0 -> 1017 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered-open@3x.pngbin0 -> 1669 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered.pngbin0 -> 432 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered@2x.pngbin0 -> 1017 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered@3x.pngbin0 -> 1669 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-open-pressed.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-open-pressed@2x.pngbin0 -> 417 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-open-pressed@3x.pngbin0 -> 628 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-open.pngbin0 -> 450 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-open@2x.pngbin0 -> 1004 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-open@3x.pngbin0 -> 1677 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-pressed.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-pressed@2x.pngbin0 -> 417 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background-pressed@3x.pngbin0 -> 628 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background.pngbin0 -> 450 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background@2x.pngbin0 -> 1004 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-background@3x.pngbin0 -> 1677 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-disabled.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-disabled@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-disabled@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-focused.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-focused@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-focused@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered-open.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered-open@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered-open@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open-pressed.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open-pressed@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open-pressed@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-pressed.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-pressed@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator-pressed@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/combobox-indicator@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-hovered-open.pngbin0 -> 389 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-hovered-open@2x.pngbin0 -> 932 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-hovered-open@3x.pngbin0 -> 1493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open-pressed.pngbin0 -> 389 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open-pressed@2x.pngbin0 -> 932 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open-pressed@3x.pngbin0 -> 1493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open.pngbin0 -> 389 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open@2x.pngbin0 -> 932 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open@3x.pngbin0 -> 1493 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-hovered-open.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-hovered-open@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-hovered-open@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open-pressed.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open-pressed@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open-pressed@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open@2x.pngbin0 -> 171 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open@3x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-hovered-open.pngbin0 -> 4029 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-hovered-open@2x.pngbin0 -> 8092 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-hovered-open@3x.pngbin0 -> 15720 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open-pressed.pngbin0 -> 4029 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open-pressed@2x.pngbin0 -> 8092 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open-pressed@3x.pngbin0 -> 15720 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open.pngbin0 -> 4029 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open@2x.pngbin0 -> 8092 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open@3x.pngbin0 -> 15720 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@2x.pngbin0 -> 292 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@3x.pngbin0 -> 354 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered.pngbin0 -> 406 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@2x.pngbin0 -> 1090 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@3x.pngbin0 -> 1787 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed.pngbin0 -> 284 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@2x.pngbin0 -> 495 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@3x.pngbin0 -> 702 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked.pngbin0 -> 424 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@2x.pngbin0 -> 1022 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@3x.pngbin0 -> 1782 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@2x.pngbin0 -> 105 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@3x.pngbin0 -> 111 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered.pngbin0 -> 172 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@2x.pngbin0 -> 240 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@3x.pngbin0 -> 318 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@2x.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@3x.pngbin0 -> 292 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/frame-background-disabled.pngbin0 -> 356 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/frame-background-disabled@2x.pngbin0 -> 616 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/frame-background-disabled@3x.pngbin0 -> 891 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/frame-background.pngbin0 -> 356 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/frame-background@2x.pngbin0 -> 616 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/frame-background@3x.pngbin0 -> 891 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-hovered.pngbin0 -> 165 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-hovered@2x.pngbin0 -> 227 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-hovered@3x.pngbin0 -> 301 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-pressed.pngbin0 -> 178 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-pressed@2x.pngbin0 -> 244 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-pressed@3x.pngbin0 -> 327 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted.pngbin0 -> 178 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted@2x.pngbin0 -> 244 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted@3x.pngbin0 -> 327 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-hovered.pngbin0 -> 178 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-hovered@2x.pngbin0 -> 244 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-hovered@3x.pngbin0 -> 327 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-pressed.pngbin0 -> 165 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-pressed@2x.pngbin0 -> 227 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-pressed@3x.pngbin0 -> 301 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/popup-background.pngbin0 -> 3820 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/popup-background@2x.pngbin0 -> 7226 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/popup-background@3x.pngbin0 -> 13082 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@2x.pngbin0 -> 97 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@3x.pngbin0 -> 112 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove@2x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/progressbar-groove@3x.pngbin0 -> 113 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@2x.pngbin0 -> 556 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@3x.pngbin0 -> 696 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered.pngbin0 -> 613 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@2x.pngbin0 -> 1182 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@3x.pngbin0 -> 1723 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed.pngbin0 -> 530 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@2x.pngbin0 -> 993 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@3x.pngbin0 -> 1363 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@2x.pngbin0 -> 920 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@3x.pngbin0 -> 1293 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled.pngbin0 -> 341 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@2x.pngbin0 -> 532 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@3x.pngbin0 -> 700 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered.pngbin0 -> 388 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@2x.pngbin0 -> 619 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@3x.pngbin0 -> 793 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed.pngbin0 -> 412 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@2x.pngbin0 -> 710 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@3x.pngbin0 -> 953 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator.pngbin0 -> 397 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@2x.pngbin0 -> 637 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@3x.pngbin0 -> 820 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@2x.pngbin0 -> 590 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@3x.pngbin0 -> 780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@2x.pngbin0 -> 590 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@3x.pngbin0 -> 780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered.pngbin0 -> 513 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@2x.pngbin0 -> 1086 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle.pngbin0 -> 513 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@2x.pngbin0 -> 1086 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@2x.pngbin0 -> 174 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@3x.pngbin0 -> 212 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@2x.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@2x.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@2x.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@3x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@2x.pngbin0 -> 590 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@3x.pngbin0 -> 780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@2x.pngbin0 -> 590 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@3x.pngbin0 -> 780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered.pngbin0 -> 513 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@2x.pngbin0 -> 1086 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle.pngbin0 -> 513 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@2x.pngbin0 -> 1086 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@2x.pngbin0 -> 179 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@3x.pngbin0 -> 214 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@3x.pngbin0 -> 234 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@3x.pngbin0 -> 234 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove.pngbin0 -> 129 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-groove@3x.pngbin0 -> 234 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@2x.pngbin0 -> 590 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@3x.pngbin0 -> 780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered.pngbin0 -> 513 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@2x.pngbin0 -> 1086 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed.pngbin0 -> 343 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@2x.pngbin0 -> 590 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@3x.pngbin0 -> 780 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle.pngbin0 -> 513 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle@2x.pngbin0 -> 1086 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/slider-handle@3x.pngbin0 -> 1545 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-atlimit.pngbin0 -> 438 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-atlimit@2x.pngbin0 -> 992 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-atlimit@3x.pngbin0 -> 1661 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-disabled.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-disabled@2x.pngbin0 -> 408 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-disabled@3x.pngbin0 -> 617 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-hovered.pngbin0 -> 438 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-hovered@2x.pngbin0 -> 992 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-hovered@3x.pngbin0 -> 1661 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-pressed.pngbin0 -> 438 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-pressed@2x.pngbin0 -> 992 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-pressed@3x.pngbin0 -> 1661 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-hovered.pngbin0 -> 420 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-hovered@2x.pngbin0 -> 995 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-hovered@3x.pngbin0 -> 1638 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-hovered.pngbin0 -> 438 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-hovered@2x.pngbin0 -> 992 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-hovered@3x.pngbin0 -> 1661 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-pressed.pngbin0 -> 438 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-pressed@2x.pngbin0 -> 992 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-pressed@3x.pngbin0 -> 1661 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background.pngbin0 -> 438 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background@2x.pngbin0 -> 992 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-background@3x.pngbin0 -> 1661 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-atlimit.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-atlimit@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-atlimit@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-disabled.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-disabled@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-disabled@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-hovered.pngbin0 -> 166 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-hovered@2x.pngbin0 -> 222 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-hovered@3x.pngbin0 -> 281 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-pressed.pngbin0 -> 166 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-pressed@2x.pngbin0 -> 222 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-pressed@3x.pngbin0 -> 281 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-hovered.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-hovered@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-hovered@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-hovered.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-hovered@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-hovered@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-pressed.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-pressed@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-pressed@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-atlimit.pngbin0 -> 134 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-atlimit@2x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-atlimit@3x.pngbin0 -> 211 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-disabled.pngbin0 -> 134 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-disabled@2x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-disabled@3x.pngbin0 -> 211 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-hovered.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-hovered@2x.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-hovered@3x.pngbin0 -> 215 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-pressed.pngbin0 -> 134 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-pressed@2x.pngbin0 -> 183 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-pressed@3x.pngbin0 -> 215 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-hovered.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-hovered@2x.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-hovered@3x.pngbin0 -> 215 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-hovered.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-hovered@2x.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-hovered@3x.pngbin0 -> 215 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-pressed.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-pressed@2x.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-pressed@3x.pngbin0 -> 215 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon@2x.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon@3x.pngbin0 -> 215 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-atlimit.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-atlimit@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-atlimit@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-disabled.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-disabled@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-disabled@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-hovered.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-hovered@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-hovered@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-pressed.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-pressed@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-pressed@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-hovered.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-hovered@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-hovered@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-hovered.pngbin0 -> 166 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-hovered@2x.pngbin0 -> 222 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-hovered@3x.pngbin0 -> 281 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-pressed.pngbin0 -> 166 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-pressed@2x.pngbin0 -> 222 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-pressed@3x.pngbin0 -> 281 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background@2x.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background@3x.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-atlimit.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-atlimit@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-atlimit@3x.pngbin0 -> 203 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-disabled.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-disabled@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-disabled@3x.pngbin0 -> 203 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-hovered.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-hovered@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-hovered@3x.pngbin0 -> 206 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-pressed.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-pressed@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-pressed@3x.pngbin0 -> 206 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-hovered.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-hovered@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-hovered@3x.pngbin0 -> 206 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-hovered.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-hovered@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-hovered@3x.pngbin0 -> 206 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-pressed.pngbin0 -> 133 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-pressed@2x.pngbin0 -> 169 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-pressed@3x.pngbin0 -> 206 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon@3x.pngbin0 -> 206 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled.pngbin0 -> 275 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@2x.pngbin0 -> 402 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@3x.pngbin0 -> 516 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered.pngbin0 -> 303 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@2x.pngbin0 -> 459 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@3x.pngbin0 -> 586 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed.pngbin0 -> 303 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@2x.pngbin0 -> 480 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@3x.pngbin0 -> 600 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@2x.pngbin0 -> 425 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@3x.pngbin0 -> 556 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@2x.pngbin0 -> 530 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@3x.pngbin0 -> 702 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered.pngbin0 -> 376 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@2x.pngbin0 -> 591 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@3x.pngbin0 -> 788 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed.pngbin0 -> 410 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@2x.pngbin0 -> 646 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@3x.pngbin0 -> 820 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background.pngbin0 -> 390 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background@2x.pngbin0 -> 626 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-background@3x.pngbin0 -> 804 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled.pngbin0 -> 250 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@2x.pngbin0 -> 716 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@3x.pngbin0 -> 1115 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered.pngbin0 -> 397 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@2x.pngbin0 -> 816 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@3x.pngbin0 -> 1180 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed.pngbin0 -> 407 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@2x.pngbin0 -> 806 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@3x.pngbin0 -> 1215 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked.pngbin0 -> 250 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@2x.pngbin0 -> 716 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@3x.pngbin0 -> 1115 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@2x.pngbin0 -> 270 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@3x.pngbin0 -> 376 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@2x.pngbin0 -> 305 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@3x.pngbin0 -> 397 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@2x.pngbin0 -> 307 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@3x.pngbin0 -> 400 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle.pngbin0 -> 196 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle@2x.pngbin0 -> 275 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/switch-handle@3x.pngbin0 -> 371 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled.pngbin0 -> 528 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@2x.pngbin0 -> 1231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@3x.pngbin0 -> 1957 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-focused.pngbin0 -> 485 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@2x.pngbin0 -> 1114 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@3x.pngbin0 -> 1803 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered.pngbin0 -> 528 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@2x.pngbin0 -> 1231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@3x.pngbin0 -> 1957 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background.pngbin0 -> 528 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background@2x.pngbin0 -> 1231 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textarea-background@3x.pngbin0 -> 1957 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled.pngbin0 -> 428 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@2x.pngbin0 -> 984 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@3x.pngbin0 -> 1548 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-focused.pngbin0 -> 398 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@2x.pngbin0 -> 895 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@3x.pngbin0 -> 1354 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered.pngbin0 -> 431 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@2x.pngbin0 -> 962 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@3x.pngbin0 -> 1529 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background.pngbin0 -> 430 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background@2x.pngbin0 -> 966 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/textfield-background@3x.pngbin0 -> 1529 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-disabled.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-disabled@2x.pngbin0 -> 285 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-disabled@3x.pngbin0 -> 387 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-hovered.pngbin0 -> 428 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-hovered@2x.pngbin0 -> 1007 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-hovered@3x.pngbin0 -> 1598 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-pressed.pngbin0 -> 281 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-pressed@2x.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-pressed@3x.pngbin0 -> 686 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked.pngbin0 -> 432 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked@2x.pngbin0 -> 886 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked@3x.pngbin0 -> 1557 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-disabled.pngbin0 -> 89 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-disabled@2x.pngbin0 -> 103 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-disabled@3x.pngbin0 -> 110 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-hovered.pngbin0 -> 173 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-hovered@2x.pngbin0 -> 237 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-hovered@3x.pngbin0 -> 306 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-pressed.pngbin0 -> 161 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-pressed@2x.pngbin0 -> 221 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/light/images/toolbutton-background-pressed@3x.pngbin0 -> 280 bytes
-rw-r--r--src/quickcontrols/fluentwinui3/qquickfluentwinui3theme.cpp142
-rw-r--r--src/quickcontrols/fluentwinui3/qquickfluentwinui3theme_p.h33
-rw-r--r--src/quickcontrols/fluentwinui3/qtquickcontrols2fluentwinui3styleplugin.cpp56
-rw-r--r--src/quickcontrols/fusion/CMakeLists.txt1
-rw-r--r--src/quickcontrols/fusion/CheckBox.qml1
-rw-r--r--src/quickcontrols/fusion/ComboBox.qml6
-rw-r--r--src/quickcontrols/fusion/Dialog.qml2
-rw-r--r--src/quickcontrols/fusion/Tumbler.qml8
-rw-r--r--src/quickcontrols/fusion/impl/CheckIndicator.qml4
-rw-r--r--src/quickcontrols/fusion/impl/RadioIndicator.qml2
-rw-r--r--src/quickcontrols/imagine/CMakeLists.txt1
-rw-r--r--src/quickcontrols/imagine/Dialog.qml2
-rw-r--r--src/quickcontrols/imagine/Tumbler.qml6
-rw-r--r--src/quickcontrols/ios/BusyIndicator.qml2
-rw-r--r--src/quickcontrols/ios/CMakeLists.txt4
-rw-r--r--src/quickcontrols/ios/CheckBox.qml4
-rw-r--r--src/quickcontrols/ios/CheckDelegate.qml10
-rw-r--r--src/quickcontrols/ios/ComboBox.qml8
-rw-r--r--src/quickcontrols/ios/Dial.qml4
-rw-r--r--src/quickcontrols/ios/Dialog.qml4
-rw-r--r--src/quickcontrols/ios/DialogButtonBox.qml8
-rw-r--r--src/quickcontrols/ios/Drawer.qml4
-rw-r--r--src/quickcontrols/ios/Frame.qml2
-rw-r--r--src/quickcontrols/ios/GroupBox.qml2
-rw-r--r--src/quickcontrols/ios/ItemDelegate.qml6
-rw-r--r--src/quickcontrols/ios/Menu.qml4
-rw-r--r--src/quickcontrols/ios/MenuBar.qml2
-rw-r--r--src/quickcontrols/ios/MenuItem.qml4
-rw-r--r--src/quickcontrols/ios/MenuSeparator.qml4
-rw-r--r--src/quickcontrols/ios/PageIndicator.qml4
-rw-r--r--src/quickcontrols/ios/Popup.qml4
-rw-r--r--src/quickcontrols/ios/ProgressBar.qml12
-rw-r--r--src/quickcontrols/ios/RadioButton.qml4
-rw-r--r--src/quickcontrols/ios/RadioDelegate.qml10
-rw-r--r--src/quickcontrols/ios/RangeSlider.qml16
-rw-r--r--src/quickcontrols/ios/ScrollBar.qml4
-rw-r--r--src/quickcontrols/ios/ScrollIndicator.qml4
-rw-r--r--src/quickcontrols/ios/SelectionRectangle.qml4
-rw-r--r--src/quickcontrols/ios/Slider.qml12
-rw-r--r--src/quickcontrols/ios/SpinBox.qml12
-rw-r--r--src/quickcontrols/ios/SwipeDelegate.qml6
-rw-r--r--src/quickcontrols/ios/Switch.qml8
-rw-r--r--src/quickcontrols/ios/SwitchDelegate.qml14
-rw-r--r--src/quickcontrols/ios/TabBar.qml2
-rw-r--r--src/quickcontrols/ios/ToolBar.qml2
-rw-r--r--src/quickcontrols/ios/ToolTip.qml4
-rw-r--r--src/quickcontrols/ios/TreeViewDelegate.qml10
-rw-r--r--src/quickcontrols/ios/impl/DialogButtonBoxDelegate.qml6
-rw-r--r--src/quickcontrols/macos/BusyIndicator.qml2
-rw-r--r--src/quickcontrols/macos/CMakeLists.txt16
-rw-r--r--src/quickcontrols/macos/DelayButton.qml4
-rw-r--r--src/quickcontrols/macos/Menu.qml83
-rw-r--r--src/quickcontrols/macos/MenuBar.qml35
-rw-r--r--src/quickcontrols/macos/MenuBarItem.qml46
-rw-r--r--src/quickcontrols/macos/MenuItem.qml75
-rw-r--r--src/quickcontrols/macos/MenuSeparator.qml24
-rw-r--r--src/quickcontrols/macos/RangeSlider.qml6
-rw-r--r--src/quickcontrols/macos/ScrollIndicator.qml42
-rw-r--r--src/quickcontrols/macos/images/checkmark.pngbin0 -> 210 bytes
-rw-r--r--src/quickcontrols/macos/images/checkmark@2x.pngbin0 -> 289 bytes
-rw-r--r--src/quickcontrols/macos/images/checkmark@3x.pngbin0 -> 359 bytes
-rw-r--r--src/quickcontrols/macos/images/menuarrow.pngbin0 -> 183 bytes
-rw-r--r--src/quickcontrols/macos/images/menuarrow@2x.pngbin0 -> 266 bytes
-rw-r--r--src/quickcontrols/macos/images/menuarrow@3x.pngbin0 -> 260 bytes
-rw-r--r--src/quickcontrols/macos/impl/CMakeLists.txt1
-rw-r--r--src/quickcontrols/macos/impl/CheckIndicator.qml21
-rw-r--r--src/quickcontrols/macos/impl/SwitchHandle.qml2
-rw-r--r--src/quickcontrols/macos/impl/SwitchIndicator.qml8
-rw-r--r--src/quickcontrols/material/Button.qml5
-rw-r--r--src/quickcontrols/material/CMakeLists.txt1
-rw-r--r--src/quickcontrols/material/Dialog.qml4
-rw-r--r--src/quickcontrols/material/Tumbler.qml8
-rw-r--r--src/quickcontrols/material/impl/CursorDelegate.qml2
-rw-r--r--src/quickcontrols/qquickattachedpropertypropagator.cpp2
-rw-r--r--src/quickcontrols/qquickstyle.cpp3
-rw-r--r--src/quickcontrols/qquickstyleplugin.cpp2
-rw-r--r--src/quickcontrols/qt_cmdline.cmake1
-rw-r--r--src/quickcontrols/universal/CMakeLists.txt1
-rw-r--r--src/quickcontrols/universal/Dialog.qml2
-rw-r--r--src/quickcontrols/universal/Tumbler.qml6
-rw-r--r--src/quickcontrols/windows/CMakeLists.txt13
-rw-r--r--src/quickcontrols/windows/Menu.qml78
-rw-r--r--src/quickcontrols/windows/MenuBar.qml35
-rw-r--r--src/quickcontrols/windows/MenuBarItem.qml47
-rw-r--r--src/quickcontrols/windows/MenuItem.qml74
-rw-r--r--src/quickcontrols/windows/MenuSeparator.qml23
-rw-r--r--src/quickcontrols/windows/RangeSlider.qml4
-rw-r--r--src/quickcontrols/windows/ScrollIndicator.qml42
-rw-r--r--src/quickcontrols/windows/images/checkmark.pngbin0 -> 200 bytes
-rw-r--r--src/quickcontrols/windows/images/checkmark@2x.pngbin0 -> 252 bytes
-rw-r--r--src/quickcontrols/windows/images/checkmark@3x.pngbin0 -> 321 bytes
-rw-r--r--src/quickcontrols/windows/images/menuarrow.pngbin0 -> 165 bytes
-rw-r--r--src/quickcontrols/windows/images/menuarrow@2x.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols/windows/images/menuarrow@3x.pngbin0 -> 205 bytes
-rw-r--r--src/quickcontrols/windows/impl/CMakeLists.txt1
-rw-r--r--src/quickcontrols/windows/impl/CheckIndicator.qml21
-rw-r--r--src/quickcontrolsimpl/CMakeLists.txt1
-rw-r--r--src/quickcontrolsimpl/qquickcolorimage.cpp4
-rw-r--r--src/quickcontrolsimpl/qquickiconimage.cpp6
-rw-r--r--src/quickcontrolsimpl/qquickimageselector.cpp2
-rw-r--r--src/quickcontrolsimpl/qquickninepatchimage.cpp6
-rw-r--r--src/quickcontrolsimpl/qquicktumblerview.cpp2
-rw-r--r--src/quickdialogs/quickdialogs/CMakeLists.txt2
-rw-r--r--src/quickdialogs/quickdialogs/qquickabstractdialog.cpp2
-rw-r--r--src/quickdialogs/quickdialogs/qquickabstractdialog_p.h3
-rw-r--r--src/quickdialogs/quickdialogs/qquickfiledialog.cpp3
-rw-r--r--src/quickdialogs/quickdialogs/qquickfolderdialog.cpp2
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt1
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl.cpp14
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickfolderbreadcrumbbar.cpp12
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickfolderdialogimpl.cpp6
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickfontdialogimpl.cpp2
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickplatformcolordialog.cpp2
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickplatformfiledialog.cpp2
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickplatformfolderdialog.cpp2
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickplatformfontdialog.cpp2
-rw-r--r--src/quickdialogs/quickdialogsquickimpl/qquickplatformmessagedialog.cpp2
-rw-r--r--src/quickdialogs/quickdialogsutils/CMakeLists.txt1
-rw-r--r--src/quickdialogs/quickdialogsutils/qquickfilenamefilter.cpp2
-rw-r--r--src/quicklayouts/CMakeLists.txt1
-rw-r--r--src/quicklayouts/qquicklayout.cpp61
-rw-r--r--src/quicklayouts/qquicklayout_p.h28
-rw-r--r--src/quicklayouts/qquicklayoutitemproxy.cpp2
-rw-r--r--src/quicknativestyle/controls/DefaultSpinBox.qml1
-rw-r--r--src/quicknativestyle/qstyle/qquickcommonstyle.cpp6
-rw-r--r--src/quickshapes/CMakeLists.txt3
-rw-r--r--src/quickshapes/qquickshape.cpp130
-rw-r--r--src/quickshapes/qquickshape_p.h11
-rw-r--r--src/quickshapes/qquickshape_p_p.h14
-rw-r--r--src/quickshapes/qquickshapecurverenderer.cpp70
-rw-r--r--src/quickshapes/qquickshapecurverenderer_p.h16
-rw-r--r--src/quickshapes/qquickshapegenericrenderer.cpp305
-rw-r--r--src/quickshapes/qquickshapegenericrenderer_p.h76
-rw-r--r--src/quickshapes/qquickshapesoftwarerenderer.cpp21
-rw-r--r--src/quickshapes/qquickshapesoftwarerenderer_p.h3
-rw-r--r--src/quickshapes/shaders_ng/conicalgradient.frag1
-rw-r--r--src/quickshapes/shaders_ng/conicalgradient.vert4
-rw-r--r--src/quickshapes/shaders_ng/lineargradient.frag1
-rw-r--r--src/quickshapes/shaders_ng/lineargradient.vert4
-rw-r--r--src/quickshapes/shaders_ng/radialgradient.frag1
-rw-r--r--src/quickshapes/shaders_ng/radialgradient.vert4
-rw-r--r--src/quickshapes/shaders_ng/texturefill.frag25
-rw-r--r--src/quickshapes/shaders_ng/texturefill.vert31
-rw-r--r--src/quicktemplates/CMakeLists.txt9
-rw-r--r--src/quicktemplates/qquickabstractbutton.cpp93
-rw-r--r--src/quicktemplates/qquickabstractbutton_p.h2
-rw-r--r--src/quicktemplates/qquickabstractbutton_p_p.h1
-rw-r--r--src/quicktemplates/qquickaction.cpp7
-rw-r--r--src/quicktemplates/qquickapplicationwindow.cpp47
-rw-r--r--src/quicktemplates/qquickbuttongroup.cpp4
-rw-r--r--src/quicktemplates/qquickcombobox.cpp2
-rw-r--r--src/quicktemplates/qquickcontrol.cpp31
-rw-r--r--src/quicktemplates/qquickcontrol_p_p.h2
-rw-r--r--src/quicktemplates/qquickdialog.cpp28
-rw-r--r--src/quicktemplates/qquickdialog_p.h27
-rw-r--r--src/quicktemplates/qquickdialog_p_p.h2
-rw-r--r--src/quicktemplates/qquickdrawer.cpp8
-rw-r--r--src/quicktemplates/qquickdrawer_p_p.h2
-rw-r--r--src/quicktemplates/qquickheaderview.cpp82
-rw-r--r--src/quicktemplates/qquickheaderview_p.h14
-rw-r--r--src/quicktemplates/qquickheaderview_p_p.h9
-rw-r--r--src/quicktemplates/qquickmenu.cpp737
-rw-r--r--src/quicktemplates/qquickmenu_p.h3
-rw-r--r--src/quicktemplates/qquickmenu_p_p.h40
-rw-r--r--src/quicktemplates/qquickmenubar.cpp565
-rw-r--r--src/quicktemplates/qquickmenubar_p.h3
-rw-r--r--src/quicktemplates/qquickmenubar_p_p.h35
-rw-r--r--src/quicktemplates/qquickmenubaritem.cpp1
-rw-r--r--src/quicktemplates/qquickmenuitem.cpp79
-rw-r--r--src/quicktemplates/qquickmenuitem_p.h12
-rw-r--r--src/quicktemplates/qquickmenuitem_p_p.h1
-rw-r--r--src/quicktemplates/qquicknativeicon.cpp50
-rw-r--r--src/quicktemplates/qquicknativeicon_p.h57
-rw-r--r--src/quicktemplates/qquicknativeiconloader.cpp66
-rw-r--r--src/quicktemplates/qquicknativeiconloader_p.h54
-rw-r--r--src/quicktemplates/qquicknativemenuitem.cpp329
-rw-r--r--src/quicktemplates/qquicknativemenuitem_p.h81
-rw-r--r--src/quicktemplates/qquickoverlay.cpp5
-rw-r--r--src/quicktemplates/qquickpage.cpp5
-rw-r--r--src/quicktemplates/qquickpage_p.h3
-rw-r--r--src/quicktemplates/qquickpane.cpp2
-rw-r--r--src/quicktemplates/qquickpopup.cpp379
-rw-r--r--src/quicktemplates/qquickpopup_p.h20
-rw-r--r--src/quicktemplates/qquickpopup_p_p.h19
-rw-r--r--src/quicktemplates/qquickpopupitem.cpp2
-rw-r--r--src/quicktemplates/qquickpopuppositioner.cpp59
-rw-r--r--src/quicktemplates/qquickpopupwindow.cpp265
-rw-r--r--src/quicktemplates/qquickpopupwindow_p_p.h57
-rw-r--r--src/quicktemplates/qquickrangeslider.cpp2
-rw-r--r--src/quicktemplates/qquickselectionrectangle.cpp20
-rw-r--r--src/quicktemplates/qquickshortcutcontext.cpp2
-rw-r--r--src/quicktemplates/qquickslider.cpp2
-rw-r--r--src/quicktemplates/qquickspinbox.cpp15
-rw-r--r--src/quicktemplates/qquicksplitview.cpp6
-rw-r--r--src/quicktemplates/qquickswipedelegate.cpp4
-rw-r--r--src/quicktemplates/qquicktextarea.cpp11
-rw-r--r--src/quicktemplates/qquicktextarea_p_p.h2
-rw-r--r--src/quicktemplates/qquicktextfield.cpp11
-rw-r--r--src/quicktemplates/qquicktextfield_p_p.h2
-rw-r--r--src/quicktemplates/qquicktooltip.cpp7
-rw-r--r--src/quicktemplates/qquicktumbler.cpp2
-rw-r--r--src/quicktestutils/quick/visualtestutils_p.h6
-rw-r--r--src/quickvectorimage/CMakeLists.txt2
-rw-r--r--src/quickvectorimage/generator/qquickgenerator.cpp5
-rw-r--r--src/quickvectorimage/generator/qquickgenerator_p.h6
-rw-r--r--src/quickvectorimage/generator/qquickitemgenerator.cpp6
-rw-r--r--src/quickvectorimage/generator/qquicknodeinfo_p.h14
-rw-r--r--src/quickvectorimage/generator/qquickqmlgenerator.cpp145
-rw-r--r--src/quickvectorimage/generator/qquickqmlgenerator_p.h14
-rw-r--r--src/quickvectorimage/generator/qsvgvisitorimpl.cpp404
-rw-r--r--src/quickvectorimage/generator/qsvgvisitorimpl_p.h2
-rw-r--r--src/quickvectorimage/qquickvectorimage.cpp124
-rw-r--r--src/quickvectorimage/qquickvectorimage_p.h28
-rw-r--r--src/quickvectorimage/qquickvectorimage_p_p.h2
-rw-r--r--src/quickwidgets/CMakeLists.txt1
-rw-r--r--src/quickwidgets/qquickwidget.cpp10
-rw-r--r--tests/auto/cmake/CMakeLists.txt7
-rw-r--r--tests/auto/cmake/shared_qml_module/CMakeLists.txt14
-rw-r--r--tests/auto/cmake/shared_qml_module/Scheduler/CMakeLists.txt33
-rw-r--r--tests/auto/cmake/shared_qml_module/Scheduler/MainScreen.qml5
-rw-r--r--tests/auto/cmake/shared_qml_module/Scheduler/schedulerglobal.h15
-rw-r--r--tests/auto/cmake/shared_qml_module/Scheduler/task.cpp47
-rw-r--r--tests/auto/cmake/shared_qml_module/Scheduler/task.h34
-rw-r--r--tests/auto/cmake/shared_qml_module/SchedulerApp/CMakeLists.txt44
-rw-r--r--tests/auto/cmake/shared_qml_module/SchedulerApp/Main.qml12
-rw-r--r--tests/auto/cmake/shared_qml_module/SchedulerApp/main.cpp21
-rw-r--r--tests/auto/cmake/shared_qml_module/external/CMakeLists.txt1
-rw-r--r--tests/auto/cmake/shared_qml_module/external/nested/module/CMakeLists.txt15
-rw-r--r--tests/auto/cmake/shared_qml_module/external/nested/module/Test.qml3
-rw-r--r--tests/auto/cmake/shared_qml_module/tests/CMakeLists.txt1
-rw-r--r--tests/auto/cmake/shared_qml_module/tests/auto/CMakeLists.txt1
-rw-r--r--tests/auto/cmake/shared_qml_module/tests/auto/unit/CMakeLists.txt40
-rw-r--r--tests/auto/cmake/shared_qml_module/tests/auto/unit/dummy.cpp1
-rw-r--r--tests/auto/cmake/shared_qml_module/tests/auto/unit/tst_models.cpp45
-rw-r--r--tests/auto/cmake/test_generate_qmlls_ini/main.cpp12
-rw-r--r--tests/auto/cmake/test_javascript_files/Bad.js1
-rw-r--r--tests/auto/cmake/test_javascript_files/CMakeLists.txt30
-rw-r--r--tests/auto/cmake/test_javascript_files/Excluded.js1
-rw-r--r--tests/auto/cmake/test_javascript_files/Good.js3
-rw-r--r--tests/auto/cmake/test_javascript_files/Good.mjs1
-rw-r--r--tests/auto/cmake/test_javascript_files/Included.js1
-rw-r--r--tests/auto/cmake/test_javascript_files/lower.js1
-rw-r--r--tests/auto/qml/debugger/shared/qqmldebugprocess.cpp2
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations3
-rw-r--r--tests/auto/qml/ecmascripttests/test262runner.cpp8
-rw-r--r--tests/auto/qml/linebylinelex/BLACKLIST5
-rw-r--r--tests/auto/qml/linebylinelex/CMakeLists.txt22
-rw-r--r--tests/auto/qml/linebylinelex/tst_linebylinelex.cpp15
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp2
-rw-r--r--tests/auto/qml/qmlcachegen/CMakeLists.txt1
-rw-r--r--tests/auto/qml/qmlcachegen/data/aotstats/AotstatsClean.qml11
-rw-r--r--tests/auto/qml/qmlcachegen/data/aotstats/AotstatsMixed.qml7
-rw-r--r--tests/auto/qml/qmlcachegen/data/aotstats/cachegentest.qrc5
-rw-r--r--tests/auto/qml/qmlcachegen/data/aotstats/qmldir3
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp133
-rw-r--r--tests/auto/qml/qmlcppcodegen/CMakeLists.txt4
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt29
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/writableVariantMap.h31
-rw-r--r--tests/auto/qml/qmlcppcodegen/data/writeVariantMap.qml10
-rw-r--r--tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp17
-rw-r--r--tests/auto/qml/qmlformat/data/enumWithValues.formatted.qml12
-rw-r--r--tests/auto/qml/qmlformat/data/enumWithValues.qml12
-rw-r--r--tests/auto/qml/qmlformat/tst_qmlformat.cpp4
-rw-r--r--tests/auto/qml/qmlimportscanner/data/CompositeSingleton.json36
-rw-r--r--tests/auto/qml/qmlimportscanner/data/CompositeWithEnum.json32
-rw-r--r--tests/auto/qml/qmlimportscanner/data/CompositeWithinSingleton.json36
-rw-r--r--tests/auto/qml/qmlimportscanner/data/Drawer.qml.json32
-rw-r--r--tests/auto/qml/qmlimportscanner/data/Imports.json36
-rw-r--r--tests/auto/qml/qmlimportscanner/data/ListProperty.qml.json44
-rw-r--r--tests/auto/qml/qmlimportscanner/data/QTBUG-45916.js.json36
-rw-r--r--tests/auto/qml/qmlimportscanner/data/Simple.qml.json36
-rw-r--r--tests/auto/qml/qmlimportscanner/data/Singleton.json36
-rw-r--r--tests/auto/qml/qmlimportscanner/data/Things.json36
-rw-r--r--tests/auto/qml/qmlimportscanner/data/javascriptMethods.qml.json36
-rw-r--r--tests/auto/qml/qmlimportscanner/data/localImport.qml.json36
-rw-r--r--tests/auto/qml/qmlimportscanner/data/parentEnum.qml.json36
-rw-r--r--tests/auto/qml/qmlimportscanner/data/qmldirImportAndDepend.qml.json36
-rw-r--r--tests/auto/qml/qmlimportscanner/data/qtQmlOnly.qml.json32
-rw-r--r--tests/auto/qml/qmlimportscanner/data/rootPath.json42
-rw-r--r--tests/auto/qml/qmllint/data/Qtbug111015/qtbug111015.qmltypes8
-rw-r--r--tests/auto/qml/qmllint/data/Things/plugins.qmltypes2
-rw-r--r--tests/auto/qml/qmllint/data/functionAssign1.qml6
-rw-r--r--tests/auto/qml/qmllint/data/functionAssign2.qml7
-rw-r--r--tests/auto/qml/qmllint/data/jsonArrayIsRecognized.qml8
-rw-r--r--tests/auto/qml/qmllint/data/something.qml2
-rw-r--r--tests/auto/qml/qmllint/data/valueTypesFromString.qml7
-rw-r--r--tests/auto/qml/qmllint/lintplugin.cpp2
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp97
-rw-r--r--tests/auto/qml/qmltc_qprocess/tst_qmltc_qprocess.cpp2
-rw-r--r--tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp128
-rw-r--r--tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h45
-rw-r--r--tests/auto/qml/qqmlapplicationengine/loadFromModuleTranslationsCppType/CMakeLists.txt2
-rw-r--r--tests/auto/qml/qqmlapplicationengine/loadFromModuleTranslationsQmlType/CMakeLists.txt2
-rw-r--r--tests/auto/qml/qqmlbinding/CMakeLists.txt2
-rw-r--r--tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp16
-rw-r--r--tests/auto/qml/qqmlconnections/CMakeLists.txt1
-rw-r--r--tests/auto/qml/qqmlecmascript/data/lookupsDoNotBypassProxy.qml29
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp14
-rw-r--r--tests/auto/qml/qqmlimport/CMakeLists.txt18
-rw-r--r--tests/auto/qml/qqmlimport/data/noimport/dirimported/Dirimported.qml5
-rw-r--r--tests/auto/qml/qqmlimport/data/noimport/redirected/Redirected.qml5
-rw-r--r--tests/auto/qml/qqmlimport/data/noimport/redirected/qmldir1
-rw-r--r--tests/auto/qml/qqmlimport/qmlimports.qt.conf3
-rw-r--r--tests/auto/qml/qqmlimport/tst_qqmlimport.cpp30
-rw-r--r--tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp4
-rw-r--r--tests/auto/qml/qqmllanguage/CMakeLists.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/SingletonWithRequiredProperties/SingletonWithRequired1.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/SingletonWithRequiredProperties/SingletonWithRequired2.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/SingletonWithRequiredProperties/qmldir4
-rw-r--r--tests/auto/qml/qqmllanguage/data/asValueType.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/asValueTypeGood.qml35
-rw-r--r--tests/auto/qml/qqmllanguage/data/invokableCtors.qml12
-rw-r--r--tests/auto/qml/qqmllanguage/data/jsonArrayProperty.qml191
-rw-r--r--tests/auto/qml/qqmllanguage/data/nestedVectors.qml27
-rw-r--r--tests/auto/qml/qqmllanguage/data/optimizedSequenceShift.qml14
-rw-r--r--tests/auto/qml/qqmllanguage/testhelper/CMakeLists.txt13
-rw-r--r--tests/auto/qml/qqmllanguage/testhelper/declarativelyregistered.cpp7
-rw-r--r--tests/auto/qml/qqmllanguage/testhelper/declarativelyregistered.h20
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp8
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h101
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp316
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp6
-rw-r--r--tests/auto/qml/qqmlparser/tst_qqmlparser.cpp2
-rw-r--r--tests/auto/qml/qqmlqt/data/qtbug_125495.qml5
-rw-r--r--tests/auto/qml/qqmlqt/tst_qqmlqt.cpp14
-rw-r--r--tests/auto/qml/qqmltimer/CMakeLists.txt1
-rw-r--r--tests/auto/qml/qqmltimer/tst_qqmltimer.cpp20
-rw-r--r--tests/auto/qml/qqmlvaluetypes/data/constructors.qml14
-rw-r--r--tests/auto/qml/qqmlvaluetypes/data/matrix4x4_invokables.qml4
-rw-r--r--tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp23
-rw-r--r--tests/auto/qml/qv4estable/tst_qv4estable.cpp6
-rw-r--r--tests/auto/qml/qv4mm/data/storeLocal.qml34
-rw-r--r--tests/auto/qml/qv4mm/tst_qv4mm.cpp228
-rw-r--r--tests/auto/qmldom/domdata/domitem/crashes/bracketsInBinding.qml5
-rw-r--r--tests/auto/qmldom/domdata/domitem/lambdas.qml41
-rw-r--r--tests/auto/qmldom/domitem/tst_qmldomitem.h476
-rw-r--r--tests/auto/qmldom/reformatter/tst_reformatter.h7
-rw-r--r--tests/auto/qmlls/modules/data/renameUsages/RenameMe.qml5
-rw-r--r--tests/auto/qmlls/modules/data/renameUsages/RenameMe2.ui.qml5
-rw-r--r--tests/auto/qmlls/modules/data/renameUsages/main.qml6
-rw-r--r--tests/auto/qmlls/modules/tst_qmlls_modules.cpp77
-rw-r--r--tests/auto/qmlls/qqmlcodemodel/data/FileA.qml5
-rw-r--r--tests/auto/qmlls/qqmlcodemodel/data/FileA2.qml5
-rw-r--r--tests/auto/qmlls/qqmlcodemodel/data/FileB.qml5
-rw-r--r--tests/auto/qmlls/qqmlcodemodel/tst_qmlls_qqmlcodemodel.cpp54
-rw-r--r--tests/auto/qmlls/qqmlcodemodel/tst_qmlls_qqmlcodemodel.h2
-rw-r--r--tests/auto/qmlls/utils/CMakeLists.txt15
-rw-r--r--tests/auto/qmlls/utils/data/highlights/identifiers.qml37
-rw-r--r--tests/auto/qmlls/utils/data/renaming/RenameMe.qml5
-rw-r--r--tests/auto/qmlls/utils/data/renaming/RenameMe2.ui.qml5
-rw-r--r--tests/auto/qmlls/utils/data/renaming/RenamedByQmldir.qml4
-rw-r--r--tests/auto/qmlls/utils/data/renaming/UnrelatedFile.qml0
-rw-r--r--tests/auto/qmlls/utils/data/renaming/main.qml7
-rw-r--r--tests/auto/qmlls/utils/data/renaming/qmldir6
-rw-r--r--tests/auto/qmlls/utils/tst_qmlls_documentationHints.cpp134
-rw-r--r--tests/auto/qmlls/utils/tst_qmlls_documentationHints.h24
-rw-r--r--tests/auto/qmlls/utils/tst_qmlls_utils.cpp976
-rw-r--r--tests/auto/qmlls/utils/tst_qmlls_utils.h3
-rw-r--r--tests/auto/quick/CMakeLists.txt1
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-qml/BLACKLIST5
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp1
-rw-r--r--tests/auto/quick/platform/CMakeLists.txt6
-rw-r--r--tests/auto/quick/platform/android/CMakeLists.txt4
-rw-r--r--tests/auto/quick/platform/android/qtandroiditemmodel/CMakeLists.txt25
-rw-r--r--tests/auto/quick/platform/android/qtandroiditemmodel/testdata/src/org/qtproject/qt/android/tests/TestModel.java120
-rw-r--r--tests/auto/quick/platform/android/qtandroiditemmodel/tst_qtandroiditemmodel.cpp182
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp22
-rw-r--r--tests/auto/quick/qquickanimations/tst_qquickanimations.cpp81
-rw-r--r--tests/auto/quick/qquickapplication/BLACKLIST4
-rw-r--r--tests/auto/quick/qquickapplication/tst_qquickapplication.cpp2
-rw-r--r--tests/auto/quick/qquickflickable/BLACKLIST4
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp2
-rw-r--r--tests/auto/quick/qquickimage/data/multiframeAsyncRetain.qml7
-rw-r--r--tests/auto/quick/qquickimage/tst_qquickimage.cpp86
-rw-r--r--tests/auto/quick/qquickitem/tst_qquickitem.cpp2
-rw-r--r--tests/auto/quick/qquickitem2/data/embedded_FocusScope.qml37
-rw-r--r--tests/auto/quick/qquickitem2/data/mapCoordinatesWithWindows.qml20
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp11
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml38
-rw-r--r--tests/auto/quick/qquicklistview/BLACKLIST4
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp2
-rw-r--r--tests/auto/quick/qquicklistview2/data/nestedSnap.qml63
-rw-r--r--tests/auto/quick/qquicklistview2/data/singletonModelLifetime.qml2
-rw-r--r--tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp64
-rw-r--r--tests/auto/quick/qquickpath/tst_qquickpath.cpp126
-rw-r--r--tests/auto/quick/qquickpathview/tst_qquickpathview.cpp6
-rw-r--r--tests/auto/quick/qquickpixmapcache/data/slowLoading.qml13
-rw-r--r--tests/auto/quick/qquickpixmapcache/deviceloadingimage.cpp35
-rw-r--r--tests/auto/quick/qquickpixmapcache/deviceloadingimage.h6
-rw-r--r--tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp60
-rw-r--r--tests/auto/quick/qquickshape/data/filltransform.qml58
-rw-r--r--tests/auto/quick/qquickshape/tst_qquickshape.cpp37
-rw-r--r--tests/auto/quick/qquickstates/data/anchorRewindBug3.qml38
-rw-r--r--tests/auto/quick/qquickstates/tst_qquickstates.cpp25
-rw-r--r--tests/auto/quick/qquicktableview/data/reordertableview.qml52
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp247
-rw-r--r--tests/auto/quick/qquicktext/BLACKLIST1
-rw-r--r--tests/auto/quick/qquicktextdocument/data/initialText.qml16
-rw-r--r--tests/auto/quick/qquicktextdocument/data/text.qml1
-rw-r--r--tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp40
-rw-r--r--tests/auto/quick/qquicktextedit/data/hAlignVisual.qml6
-rw-r--r--tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp56
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp11
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp10
-rw-r--r--tests/auto/quick/qquickwindowcontainer/tst_qquickwindowcontainer.cpp8
-rw-r--r--tests/auto/quickcontrols/accessibility/data/actionAccessibility/button.qml12
-rw-r--r--tests/auto/quickcontrols/accessibility/tst_accessibility.cpp22
-rw-r--r--tests/auto/quickcontrols/controls/CMakeLists.txt1
-rw-r--r--tests/auto/quickcontrols/controls/basic/BLACKLIST5
-rw-r--r--tests/auto/quickcontrols/controls/basic/tst_basic.cpp3
-rw-r--r--tests/auto/quickcontrols/controls/data/combobox/shader.frag19
-rw-r--r--tests/auto/quickcontrols/controls/data/combobox/shader.frag.qsbbin0 -> 577 bytes
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_abstractbutton.qml174
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_button.qml17
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_checkbox.qml4
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_combobox.qml88
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_control.qml4
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_delaybutton.qml6
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_radiobutton.qml4
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml53
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_stackview.qml2
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_swipedelegate.qml25
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_swipeview.qml2
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_switch.qml12
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_switchdelegate.qml12
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_tabbar.qml10
-rw-r--r--tests/auto/quickcontrols/controls/data/tst_tumbler.qml188
-rw-r--r--tests/auto/quickcontrols/controls/fluentwinui3/BLACKLIST14
-rw-r--r--tests/auto/quickcontrols/controls/fluentwinui3/CMakeLists.txt38
-rw-r--r--tests/auto/quickcontrols/controls/fluentwinui3/dependencies.qml6
-rw-r--r--tests/auto/quickcontrols/controls/fluentwinui3/dummy_imports.qml12
-rw-r--r--tests/auto/quickcontrols/controls/fluentwinui3/tst_fluentwinui3.cpp13
-rw-r--r--tests/auto/quickcontrols/controls/fusion/tst_fusion.cpp3
-rw-r--r--tests/auto/quickcontrols/controls/imagine/tst_imagine.cpp3
-rw-r--r--tests/auto/quickcontrols/controls/ios/tst_ios.cpp3
-rw-r--r--tests/auto/quickcontrols/controls/macos/tst_macos.cpp3
-rw-r--r--tests/auto/quickcontrols/controls/material/tst_material.cpp3
-rw-r--r--tests/auto/quickcontrols/controls/universal/tst_universal.cpp3
-rw-r--r--tests/auto/quickcontrols/controls/windows/tst_windows.cpp3
-rw-r--r--tests/auto/quickcontrols/focus/tst_focus.cpp39
-rw-r--r--tests/auto/quickcontrols/font/tst_font.cpp2
-rw-r--r--tests/auto/quickcontrols/palette/data/comboBoxPopupWithThemeDefault.qml17
-rw-r--r--tests/auto/quickcontrols/palette/data/toolTipPaletteUpdate.qml19
-rw-r--r--tests/auto/quickcontrols/palette/tst_palette.cpp64
-rw-r--r--tests/auto/quickcontrols/qquickapplicationwindow/data/backgroundSize.qml1
-rw-r--r--tests/auto/quickcontrols/qquickapplicationwindow/data/explicitBackgroundSizeBinding.qml21
-rw-r--r--tests/auto/quickcontrols/qquickapplicationwindow/tst_qquickapplicationwindow.cpp21
-rw-r--r--tests/auto/quickcontrols/qquickdrawer/tst_qquickdrawer.cpp3
-rw-r--r--tests/auto/quickcontrols/qquickiconlabel/tst_qquickiconlabel.cpp2
-rw-r--r--tests/auto/quickcontrols/qquickmaterialstyle/tst_qquickmaterialstyle.cpp16
-rw-r--r--tests/auto/quickcontrols/qquickmenu/data/nativeDynamicSubmenus.qml53
-rw-r--r--tests/auto/quickcontrols/qquickmenu/data/nativeEmptyMenu.qml51
-rw-r--r--tests/auto/quickcontrols/qquickmenu/data/nativeMenuSeparator.qml43
-rw-r--r--tests/auto/quickcontrols/qquickmenu/data/nativeMixedItems.qml69
-rw-r--r--tests/auto/quickcontrols/qquickmenu/data/nativeStatic.qml53
-rw-r--r--tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp798
-rw-r--r--tests/auto/quickcontrols/qquickmenubar/data/hoverAfterClosingWithEscape.qml5
-rw-r--r--tests/auto/quickcontrols/qquickmenubar/data/invaliddelegate.qml40
-rw-r--r--tests/auto/quickcontrols/qquickmenubar/data/menubarAsHeader.qml64
-rw-r--r--tests/auto/quickcontrols/qquickmenubar/data/menubaritems.qml (renamed from tests/auto/quickcontrols/qquickmenubar/data/menubar.qml)11
-rw-r--r--tests/auto/quickcontrols/qquickmenubar/data/menus.qml85
-rw-r--r--tests/auto/quickcontrols/qquickmenubar/data/mixed.qml55
-rw-r--r--tests/auto/quickcontrols/qquickmenubar/data/nodelegate.qml40
-rw-r--r--tests/auto/quickcontrols/qquickmenubar/data/showandhide.qml40
-rw-r--r--tests/auto/quickcontrols/qquickmenubar/tst_qquickmenubar.cpp1018
-rw-r--r--tests/auto/quickcontrols/qquickpopup/BLACKLIST4
-rw-r--r--tests/auto/quickcontrols/qquickpopup/data/popupCenterIn.qml22
-rw-r--r--tests/auto/quickcontrols/qquickpopup/data/popupWindowFocusHandling.qml28
-rw-r--r--tests/auto/quickcontrols/qquickpopup/data/popupWithButtonInBackground.qml28
-rw-r--r--tests/auto/quickcontrols/qquickpopup/data/reparentingPopup.qml48
-rw-r--r--tests/auto/quickcontrols/qquickpopup/data/simplepopup.qml22
-rw-r--r--tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp506
-rw-r--r--tests/auto/quickcontrols/qquicktextarea/tst_qquicktextarea.cpp10
-rw-r--r--tests/auto/quickcontrols/qquickuniversalstyle/tst_qquickuniversalstyle.cpp16
-rw-r--r--tests/auto/quickcontrols/snippets/tst_snippets.cpp3
-rw-r--r--tests/auto/quickdialogs/qquickfolderdialogimpl/tst_qquickfolderdialogimpl.cpp1
-rw-r--r--tests/auto/quickdialogs/qquickfontdialogimpl/BLACKLIST1
-rw-r--r--tests/auto/quickdialogs/qquickfontdialogimpl/tst_qquickfontdialogimpl.cpp2
-rw-r--r--tests/auto/quickwidgets/qquickwidget/BLACKLIST7
-rw-r--r--tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp20
-rw-r--r--tests/baseline/scenegraph/data/shape/shape_fillItem.qml177
-rw-r--r--tests/baseline/scenegraph/data/shape/shape_gradient_xf.qml81
-rw-r--r--tests/baseline/scenegraph/data/shape/shape_intersecting8.qml64
-rw-r--r--tests/baseline/scenegraph/data/shape/shape_rectangle.qml151
-rw-r--r--tests/baseline/scenegraph/data/shape/shape_spread_xf.qml47
-rw-r--r--tests/baseline/scenegraph/data/shape/shape_updatecolor.qml77
-rw-r--r--tests/baseline/scenegraph/data/shape/shape_updatefill.qml214
-rw-r--r--tests/baseline/scenegraph/data/shape/shape_updategradient.qml105
-rw-r--r--tests/baseline/scenegraph/data/shared/qt_logo.svg26
-rw-r--r--tests/baseline/scenegraph/data/shared/svg/gradientxform.svg62
-rw-r--r--tests/baseline/scenegraph/data/shared/svg/text_stroking.svg23
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-constr-201-t.svg69
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-coord-01-t.svg51
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-01-t.svg223
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-02-t.svg86
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-03-t.svg83
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-04-t.svg72
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-05-t.svg72
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-06-t.svg66
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-07-t.svg65
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-08-t.svg70
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-09-t.svg96
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-units-01-t.svg111
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-viewattr-05-t.svg90
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-desc-02-t.svg99
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-01-t.svg94
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-02-t.svg102
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-03-t.svg85
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-06-t.svg88
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-02-t.svg68
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-03-t.svg62
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-04-t.svg50
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-201-t.svg174
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-202-t.svg175
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-203-t.svg97
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-kern-01-t.svg238
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-overview-201-t.svg114
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/intro-compat-201-t.svgbin0 -> 7154 bytes
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-201-t.svg49
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-202-t.svg49
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-203-t.svg49
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-204-t.svg49
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-205-t.svg50
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-206-t.svg50
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-207-t.svg48
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-208-t.svg52
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-209-t.svg50
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-01-t.svg72
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-03-t.svg95
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-04-t.svg84
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-05-t.svg44
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-201-t.svg109
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-01-t.svg49
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-02-t.svg55
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-03-t.svg49
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-04-t.svg64
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-05-t.svg60
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-04-t.svg81
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-05-t.svg88
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-07-t.svg70
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-08-t.svg88
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-09-t.svg92
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-11-t.svg95
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-12-t.svg93
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-15-t.svg60
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-16-t.svg66
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-17-t.svg80
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-18-t.svg74
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-202-t.svg82
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-204-t.svg61
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-205-t.svg52
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-other-201-t.svg65
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-01-t.svg56
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-02-t.svg57
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-03-t.svg56
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-04-t.svg57
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-05-t.svg81
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-06-t.svg73
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-07-t.svg53
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-08-t.svg76
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-202-t.svg175
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-204-t.svg181
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-207-t.svg106
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-vfill-202-t.svg50
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-vfill-204-t.svg50
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-vfill-205-t.svg49
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-01-t.svg132
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-02-t.svg105
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-04-t.svg65
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-05-t.svg63
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-06-t.svg68
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-07-t.svg67
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-08-t.svg63
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-09-t.svg61
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-10-t.svg97
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-12-t.svg56
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-13-t.svg47
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-14-t.svg49
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-15-t.svg52
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-01-t.svg54
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-02-t.svg57
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-03-t.svg53
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-06-t.svg56
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-07-t.svg56
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-08-t.svg56
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-groups-01-t.svg74
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-groups-03-t.svg76
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-circle-01-t.svg46
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-circle-02-t.svg52
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-circle-03-t.svg86
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-ellipse-01-t.svg59
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-ellipse-02-t.svg50
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-ellipse-03-t.svg82
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-intro-01-t.svg96
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-line-01-t.svg68
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-line-02-t.svg66
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polygon-01-t.svg64
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polygon-02-t.svg63
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polyline-01-t.svg70
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polyline-02-t.svg64
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-rect-01-t.svg60
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-rect-02-t.svg55
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-rect-03-t.svg64
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-class-201-t.svg92
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-common-201-t.svg110
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-01-t.svg46
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-02-t.svg336
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-03-t.svg97
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-204-t.svg150
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-209-t.svg74
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-210-t.svg82
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-defs-01-t.svg49
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-defs-201-t.svg104
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-discard-205-t.svg72
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-discard-206-t.svg65
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-02-t.svg45
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-03-t.svg45
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-04-t.svg45
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-05-t.svg53
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-06-t.svg56
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-group-01-t.svg55
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-group-03-t.svg226
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-201-t.svg87
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-202-t.svg86
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-203-t.svg68
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-204-t.svg49
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-01-t.svg88
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-03-t.svg53
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-09-t.svg81
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-201-t.svg94
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-202-t.svg66
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-203-t.svg47
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-204-t.svg47
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-205-t.svg188
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-206-t.svg48
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-207-t.svg78
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-208-t.svg57
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-209-t.svg64
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-recursion-01-t.svg59
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-recursion-02-t.svg58
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-recursion-03-t.svg58
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/styling-inherit-01-t.svg61
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/styling-pres-01-t.svg47
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-01-t.svg63
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-07-t.svg58
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-08-t.svg75
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-201-t.svg61
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-202-t.svg895
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-201-t.svg68
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-202-t.svg152
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-205-t.svg52
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-206-t.svg71
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-207-t.svg88
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-208-t.svg79
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-209-t.svg60
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-210-t.svg66
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-221-t.svg72
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-222-t.svg63
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-edit-201-t.svg130
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-01-t.svg52
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-02-t.svg60
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-03-t.svg62
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-04-t.svg76
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-202-t.svg85
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-01-t.svg61
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-04-t.svg53
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-05-t.svg45
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-06-t.svg56
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-201-t.svg55
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-04-t.svg171
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-06-t.svg95
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-07-t.svg43
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-08-t.svg42
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-09-t.svg55
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-tselect-03-t.svg87
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-ws-01-t.svg58
-rw-r--r--tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-ws-02-t.svg65
-rw-r--r--tests/baseline/scenegraph/data/text/text_prefertypolinemetrics.qml24
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/coordsOther.qml38
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/coordsOtherCurveRenderer.qml38
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/coordsTrans.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/coordsTransCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/fillMode.qml59
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/fontsElem.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/fontsElemCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/fontsGlyph.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/fontsGlyphCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/fontsOther.qml35
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/fontsOtherCurveRenderer.qml35
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/gradientxform.qml25
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/introCompat.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/jpegRequired.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/jpegRequiredCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/paintColor.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/paintColorCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/paintFill.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/paintFillCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/paintGrad.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/paintGradCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/paintStroke.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/paintStrokeCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/paintVfill.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/paintVfillCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/pathsData.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/pathsDataCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/renderElems.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/renderElemsCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/renderGroups.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/renderGroupsCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesCircle.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesCircleCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesEllipse.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesEllipseCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesIntro.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesIntroCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesLine.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesLineCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesPolygon.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesPolygonCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesPolyline.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesPolylineCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesRect.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/shapesRectCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structCommon.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structCommonCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structCond.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structCondCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structDefs.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structDefsCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structDiscard.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structDiscardCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structFrag.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structFragCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structGroup.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structGroupCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structSvg.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structSvgCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structUse.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/structUseCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/styling.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/stylingCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textAlign.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textAlignCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textArea.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textAreaCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textIntro.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textIntroCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textOther.qml32
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textOtherCurveRenderer.qml32
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textStroke.qml6
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textText.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textTextCurveRenderer.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textWs.qml28
-rw-r--r--tests/baseline/scenegraph/data/vectorimages/textWsCurveRenderer.qml28
-rw-r--r--tests/manual/painterpathquickshape/ControlPanel.qml14
-rw-r--r--tests/manual/painterpathquickshape/ControlledShape.qml1
-rw-r--r--tests/manual/platforms/android/qml_in_android_service/.gitignore2
-rw-r--r--tests/manual/platforms/android/qml_in_android_service/CMakeLists.txt33
-rw-r--r--tests/manual/platforms/android/qml_in_android_service/Main.qml100
-rw-r--r--tests/manual/platforms/android/qml_in_android_service/main.cpp10
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/.gitignore33
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/README.md35
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/app/build.gradle83
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/AndroidManifest.xml32
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java20
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/QmlService.java204
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/layout/view_main.xml142
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/values/strings.xml12
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/backup_rules.xml10
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/data_extraction_rules.xml10
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/build.gradle4
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/gradle.properties22
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/gradle/wrapper/gradle-wrapper.properties7
-rw-r--r--tests/manual/platforms/android/qml_in_java_based_android_project/settings.gradle23
-rw-r--r--tests/manual/quickcontrols/CMakeLists.txt1
-rw-r--r--tests/manual/quickcontrols/menus/CMakeLists.txt47
-rw-r--r--tests/manual/quickcontrols/menus/Main.qml472
-rw-r--r--tests/manual/quickcontrols/menus/Menu.qml6
-rw-r--r--tests/manual/quickcontrols/menus/cppsettings.cpp43
-rw-r--r--tests/manual/quickcontrols/menus/cppsettings.h38
-rw-r--r--tests/manual/quickcontrols/menus/icons/warning.pngbin0 -> 1212 bytes
-rw-r--r--tests/manual/quickcontrols/menus/icons/warning@2x.pngbin0 -> 2118 bytes
-rw-r--r--tests/manual/quickcontrols/menus/main.cpp27
-rw-r--r--tests/manual/quickcontrols/testbench/controls/Menu.qml3
-rw-r--r--tests/manual/quickcontrols/testbench/controls/ToolBar.qml2
-rw-r--r--tests/manual/quickcontrols/testbench/testbench.qml6
-rw-r--r--tests/manual/svg/data/styling/stroking_text.svg4
-rw-r--r--tests/manual/tableview/abstracttablemodel/main.qml36
-rw-r--r--tests/manual/windowembedding/examples/clipping.qml17
-rw-r--r--tests/manual/windowembedding/examples/stacking.qml42
-rw-r--r--tests/manual/windowembedding/examples/transform.qml25
-rw-r--r--tools/qmlaotstats/CMakeLists.txt17
-rw-r--r--tools/qmlaotstats/main.cpp83
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp28
-rw-r--r--tools/qmllint/main.cpp25
-rw-r--r--tools/qmlls/qmllanguageservertool.cpp128
-rw-r--r--tools/qmltc/main.cpp3
-rw-r--r--tools/qmltc/qmltccompiler.cpp18
-rw-r--r--tools/qmltc/qmltctyperesolver.cpp2
-rw-r--r--tools/qmltc/qmltcvisitor.cpp1
-rw-r--r--tools/qmltyperegistrar/qmltyperegistrar.cpp1
-rw-r--r--tools/svgtoqml/main.cpp12
2341 files changed, 71550 insertions, 6432 deletions
diff --git a/.cmake.conf b/.cmake.conf
index b768639e74..0736c680fe 100644
--- a/.cmake.conf
+++ b/.cmake.conf
@@ -1,4 +1,4 @@
-set(QT_REPO_MODULE_VERSION "6.8.0")
+set(QT_REPO_MODULE_VERSION "6.9.0")
set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1")
set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_LEAN_HEADERS=1")
diff --git a/.gitignore b/.gitignore
index def0f040cd..e3756b608c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -372,3 +372,7 @@ CMakeLists.txt.user
# QML Language Server ini-files
.qmlls.ini
+
+# Clangd related
+.cache/*
+compile_commands.json
diff --git a/dependencies.yaml b/dependencies.yaml
index b3b18a686d..68dafb130e 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -1,16 +1,16 @@
dependencies:
../qtbase:
- ref: 4641945e45206508b44678011bb83da7722bad62
+ ref: 691f6b5b0c9dc69f8d019abc53747e7a6bbf6ef8
required: true
../qtimageformats:
- ref: 0f495cc4db125282ae5bab6e21c504c2a0520606
+ ref: 9aa5594d6180548891967fae5e73688efea354a1
required: false
../qtlanguageserver:
- ref: 19f182c85e4156917e28e1f5c14b8da2079aefd6
+ ref: 85a56bf6c8e4254045d92f9d145c552add5747b5
required: false
../qtshadertools:
- ref: 2eced24fc6550f2845f5d6de33100e7c27207008
+ ref: d119ba53667c16576c9fa894eb029833c4102835
required: false
../qtsvg:
- ref: c6fe4261bdaa4f47f779e3ef0e4de89ca80d2be7
+ ref: 8cd475dacccf6828029d998197974fad8786c7e0
required: false
diff --git a/examples/platforms/android/doc/src/qml_in_android_studio_projects.qdoc b/examples/platforms/android/doc/src/qml_in_android_studio_projects.qdoc
index be1fa8b7a2..5cd38b68ef 100644
--- a/examples/platforms/android/doc/src/qml_in_android_studio_projects.qdoc
+++ b/examples/platforms/android/doc/src/qml_in_android_studio_projects.qdoc
@@ -12,8 +12,8 @@
This example contains a QML project that you can import into Android Studio
with the \l {Qt Tools for Android Studio} plugin
- and Java and Kotlin projects that utilize the
- \l {Qt Quick View Android Class}{QtQuickView} API.
+ and Java and Kotlin projects that use the QML project as a View by
+ utilizing the \l {Qt Quick View Android Class}{QtQuickView} API.
For more information on how QML works, see the \l {Qt Qml}. This
documentation will focus on how a QML component is embedded into
@@ -37,21 +37,47 @@
\snippet android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt binding
- Inside the \c onCreate() method, an instance of
- \l {Qt Quick View Android Class}{QtQuickView} named
- \c m_qmlView is created by giving it the Java/Kotlin application Context,
- URI of the QML project's \c main.qml file and the name of the QML project's
- main library as parameters.
+ Inside the \c onCreate() method, a previously declared variable
+ \c m_qtQuickView is initialized with a new
+ \l {Qt Quick View Android Class}{QtQuickView}.
+ This new instance of \l {Qt Quick View Android Class}{QtQuickView}
+ is created by giving it the Context of the Java/Kotlin Activity as
+ an argument.
For a Java-based project:
- \snippet android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java m_qmlView
+ \snippet android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java m_qtQuickView
For a Kotlin-based project:
- \snippet android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt m_qmlView
+ \snippet android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt m_qtQuickView
- \c m_qmlView is then added to Android FrameLayout ViewGroup with
+ Previously declared variable m_mainQmlComponent is
+ initialized with new Main() object. Main is a Java class extending
+ QtQmlComponent, generated from the imported QML project.
+ This is the QML component we will be interacting with.
+
+ For a Java-based project:
+
+ \snippet android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java qmlComponent
+
+ For a Kotlin-based project (initialized when declared):
+
+ \snippet android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt qmlComponent
+
+ The \c m_mainQmlComponent is loaded into the \c m_qtQuickView through the
+ \c QtQuickView.loadComponent() method, which takes \c QtQmlComponent as an
+ argument.
+
+ For a Java-based project:
+
+ \snippet android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java loadComponent
+
+ For a Kotlin-based project:
+
+ \snippet android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt loadComponent
+
+ The \c m_qtQuickView is added to Android FrameLayout ViewGroup with
appropriate layout parameters.
For a Java-based project:
@@ -64,30 +90,29 @@
\section1 Interacting with the QML component
- To interact with the embedded QML component we first need to implement
- the \l {Qt Quick View Android Class}{QtQuickView} public interface
- \l [Qt Quick View Android Class]{public interface StatusChangeListener}{StatusChangeListener}.
+ To interact with the embedded QML component we implement the
+ \c QtQmlStatusChangeListener interface and override the onStatusChanged
+ method to get the loading status of the QtQmlComponent currently being
+ loaded into the \c m_qtQuickView.
For a Java-based project:
\code
public class MainActivity extends AppCompatActivity implements
- QtQuickView.StatusChangeListener{
+ QtQmlStatusChangeListener{
...
}
\endcode
- IFor a Kotlin-based project:
+ For a Kotlin-based project:
\code
- class MainActivity : AppCompatActivity(), QtQuickView.StatusChangeListener{
+ class MainActivity : AppCompatActivity(), QtQmlStatusChangeListener{
...
}
\endcode
- Then, define an override for the
- \l [Qt Quick View Android Class]{public interface StatusChangeListener}{StatusChangeListener}
- callback function \c onStatusChanged().
+ OnstatusChanged implementation.
For a Java-based project:
@@ -97,8 +122,9 @@
\snippet android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt onStatusChanged
- Then, set that listener to listen for status changes of \c m_qmlView
- with the \l [Qt Quick View Android Class]{public void setStatusChangeListener(StatusChangeListener listener)}{setStatusChangeListener()}.
+ The onStatusChanged method is then set as the statusChangeListener of
+ the \c QtQmlComponent with QtQmlComponent.setStatusChangeListener(
+ QtQmlStatusChangeListener onStatusChanged()).
For a Java-based project:
@@ -110,22 +136,18 @@
The overridden callback function \c onStatusChanged() receives
\c StatusChanged() signal containing the current
- \l [Qt Quick View Android Class]{Status values}{Status value} of the
- \c m_qmlView. If this
- \l [Qt Quick View Android Class]{Status values}{Status value}
- is confirmed to be
- \l [Qt Quick View Android Class]{Status values}{STATUS_READY},
- we can start interacting with the QML view.
+ status (public Enum QtQmlStatus) of the loading of the current
+ QtQmlComponent into the \c m_qtQuickView. If this \c QtQmlStatus
+ is confirmed to be \c QtQmlStatus.READY, we can start interacting
+ with the QML view.
- \section1 Getting and setting QML view property values
+ \section1 Getting and setting QML component property values
- Getting and setting QML view property values happens through the
- \l [Qt Quick View Android Class]{public <T extends Object> T getProperty(String propertyName)}{QtQuickView.getProperty()}
- and \l [Qt Quick View Android Class]{public void setProperty(String propertyName, Object value)}{QtQuickView.setProperty()}
- methods.
-
- The root object of the QML component's background color is set when a click
- event of an Android button occurs.
+ Getting and setting QML component property values happens through the
+ methods described in the \c Main.java class. In this case we use the
+ \c m_mainQmlComponent.setColorStringProperty() and
+ \c m_mainQmlComponent.getColorStringProperty() methods. These methods are
+ generated according to what properties the QML component includes.
For a Java-based project:
@@ -135,21 +157,25 @@
\snippet android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt onClickListener
- With the \l [Qt Quick View Android Class]{public void setProperty(StringpropertyName, Object value)}{QtQuickView.setProperty()}
- method we set the "colorStringFormat" property value to a random color
- value that is fetched from the project's \c Colors.java class.
+ With the \c m_mainQmlComponent.setColorStringProperty()
+ method we set the \c colorStringFormat property value of the
+ \c m_mainQmlComponent a random color value that is fetched from the
+ \c Colors.java class.
- The \l [Qt Quick View Android Class]{public <T extends Object> T getProperty (String propertyName)}{QtQuickView.getProperty()}{QtQuickView.getProperty()}
+ The \c m_mainQmlComponent.getColorStringProperty()
method is used here to fetch the current background color of the root
- object of the QML component and then show it to the user on the Android
- side of the application.
+ object of the m_mainQmlComponent and then show it to the user on the
+ Java/Kotlin Android side of the application.
\section1 Signal listeners
- \l {Qt Quick View Android Class}{QtQuickView} class offers a
- connectSignalListener() and disconnectSignalListener() methods which are
- used to connect and disconnect a signal listener to a signal that is
- declared in the QML component root object.
+ The \c QtQmlComponent class offers a
+ \c connectSignalListener() and \c disconnectSignalListener() methods which
+ are used to connect and disconnect a signal listener/s between a signal/s
+ that is/are declared in the QML component root object.
+ The \c QtQmlComponent.connectSignalListener()
+ returns a unique signal listener id which we store and use later to
+ identify and disconnect the listener.
Here we connect a signal listener to the \c onClicked() signal of the
QML component.
@@ -162,14 +188,15 @@
\snippet android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt qml signal listener
- The \c onClicked() signal is emitted every time the button on the QML UI is
- clicked. That signal is then received by this listener and the background
+ The \c onClicked() signal is emitted every time the button on the
+ QML component is clicked.
+ That signal is then received by this listener and the background
color of the layout holding the Android side of the application is set to
- a random color value fetched from the project's \c Colors.java class.
+ a random color value fetched from the \c Colors.java class.
- The \l [Qt Quick View Android Class]{public <T> int addSignalListener(String signalName, Class<T> argType, SignalListener<T> listener)}{QtQuickView.connectSignalListener()}
- returns a unique signal listener id which we store and use later to
- identify and disconnect the listener.
+ Next, the signal listener is disconnected using the
+ \c QtQmlComponent.disconnectSignalListener()
+ method by giving it the unique signal listener id.
For a Java-based project:
@@ -179,8 +206,4 @@
\snippet android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt disconnect qml signal listener
- Here, the previously connected signal listener is disconnected using the
- \l [Qt Quick View Android Class]{public boolean removeSignalListener(int signalListenerId)}{QtQuickView.disconnectSignalListener()}
- method by giving it the unique signal listener id.
-
*/
diff --git a/examples/platforms/android/qml_in_android_view/CMakeLists.txt b/examples/platforms/android/qml_in_android_view/CMakeLists.txt
index 9aed5c0a4e..db13f2e63c 100644
--- a/examples/platforms/android/qml_in_android_view/CMakeLists.txt
+++ b/examples/platforms/android/qml_in_android_view/CMakeLists.txt
@@ -15,9 +15,10 @@ qt_add_executable(qml_in_android_view
)
qt_add_qml_module(qml_in_android_view
- URI qml_in_android_view
+ URI qmlModule
VERSION 1.0
- QML_FILES main.qml
+ QML_FILES Main.qml
+ QML_FILES Second.qml
)
target_link_libraries(qml_in_android_view
diff --git a/examples/platforms/android/qml_in_android_view/main.qml b/examples/platforms/android/qml_in_android_view/Main.qml
index 3ed2b6f58b..f12861aeb9 100644
--- a/examples/platforms/android/qml_in_android_view/main.qml
+++ b/examples/platforms/android/qml_in_android_view/Main.qml
@@ -15,12 +15,12 @@ Rectangle {
Text {
id: helloText
- text: "QML"
+ text: "Main QML component"
color: "white"
font.pixelSize: 72
fontSizeMode: Text.VerticalFit
// Height is calculated based on display orientation
- // from Screen height, dividing numbers are based on what what seem
+ // from Screen height, dividing numbers are based on what seem
// to look good on most displays
height: Screen.width > Screen.height ? Screen.height / 8 : (Screen.height / 2) / 8
font.bold: true
@@ -52,6 +52,7 @@ Rectangle {
Button {
id: button
+
// Width is calculated from changeColorText which is calculated from Screen size
// dividing numbers are base on what seems to look good on most displays
width: changeColorText.width / 1.6
diff --git a/examples/platforms/android/qml_in_android_view/Second.qml b/examples/platforms/android/qml_in_android_view/Second.qml
new file mode 100644
index 0000000000..067d1921de
--- /dev/null
+++ b/examples/platforms/android/qml_in_android_view/Second.qml
@@ -0,0 +1,78 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+import QtQuick
+import QtQuick.Controls
+
+Rectangle {
+ id: secondaryRectangle
+
+ property int gridRotation: 0
+
+ color: "blue"
+
+ Text {
+ id: title
+
+ text: "Second QML component"
+ color: "white"
+ font.pixelSize: 72
+ fontSizeMode: Text.VerticalFit
+ // Height is calculated based on display orientation
+ // from Screen height, dividing numbers are based on what seem
+ // to look good on most displays
+ height: Screen.width > Screen.height ? Screen.height / 8 : (Screen.height / 2) / 8
+ font.bold: true
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ anchors.topMargin: 5
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ Text {
+ id: gridText
+
+ text: "QML Grid type"
+ fontSizeMode: Text.VerticalFit
+ font.pixelSize: 48
+ color: "white"
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: title.bottom
+ anchors.topMargin: 100
+ }
+
+ Grid {
+ id: grid
+
+ columns: 3
+ rows: 3
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: gridText.bottom
+ anchors.topMargin: 50
+ spacing: 50
+ rotation: gridRotation
+
+ Repeater {
+ id: repeater
+
+ model: [
+ "green",
+ "lightblue",
+ "grey",
+ "red",
+ "black",
+ "white",
+ "pink",
+ "yellow",
+ "orange"
+ ]
+
+ Rectangle {
+ required property string modelData
+
+ height: 50
+ width: 50
+ color: modelData
+ }
+ }
+ }
+}
diff --git a/examples/platforms/android/qml_in_java_based_android_project/app/build.gradle b/examples/platforms/android/qml_in_java_based_android_project/app/build.gradle
index 8e9ab1deb9..ab25257151 100644
--- a/examples/platforms/android/qml_in_java_based_android_project/app/build.gradle
+++ b/examples/platforms/android/qml_in_java_based_android_project/app/build.gradle
@@ -8,7 +8,7 @@ android {
defaultConfig {
applicationId "com.example.qml_in_java_based_android_project"
- minSdk 26
+ minSdk 28
targetSdk 34
versionCode 1
versionName "1.0"
diff --git a/examples/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java b/examples/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java
index e7aee43c55..039a663387 100644
--- a/examples/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java
+++ b/examples/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java
@@ -16,29 +16,34 @@ import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
-
+import org.qtproject.qt.android.QtQmlStatus;
+import org.qtproject.qt.android.QtQmlStatusChangeListener;
import org.qtproject.qt.android.QtQuickView;
-
+import org.qtproject.example.qml_in_android_view.QmlModule.Main;
+import org.qtproject.example.qml_in_android_view.QmlModule.Second;
import java.util.HashMap;
import java.util.Map;
-
// Implement QtQuickView StatusChangeListener interface to get status updates
// from the underlying QQuickView
-public class MainActivity extends AppCompatActivity implements QtQuickView.StatusChangeListener {
+public class MainActivity extends AppCompatActivity implements QtQmlStatusChangeListener {
private static final String TAG = "myTag";
private final Colors m_colors = new Colors();
- private final Map<Integer, String> m_statusNames = new HashMap<Integer, String>() {{
- put(QtQuickView.STATUS_READY, " READY");
- put(QtQuickView.STATUS_LOADING, " LOADING");
- put(QtQuickView.STATUS_ERROR, " ERROR");
- put(QtQuickView.STATUS_NULL, " NULL");
+ private final Map<QtQmlStatus, String> m_statusNames = new HashMap<QtQmlStatus, String>() {{
+ put(QtQmlStatus.READY, " READY");
+ put(QtQmlStatus.LOADING, " LOADING");
+ put(QtQmlStatus.ERROR, " ERROR");
+ put(QtQmlStatus.NULL, " NULL");
}};
private int m_qmlButtonSignalListenerId;
private LinearLayout m_mainLinear;
private FrameLayout m_qmlFrameLayout;
- private QtQuickView m_qmlView;
+ private QtQuickView m_qtQuickView;
+ //! [qmlComponent]
+ private final Main m_mainQmlComponent = new Main();
+ //! [qmlComponent]
+ private final Second m_secondQmlComponent = new Second();
private LinearLayout m_androidControlsLayout;
private TextView m_getPropertyValueText;
private TextView m_qmlStatus;
@@ -53,34 +58,44 @@ public class MainActivity extends AppCompatActivity implements QtQuickView.Statu
m_mainLinear = findViewById(R.id.mainLinear);
m_getPropertyValueText = findViewById(R.id.getPropertyValueText);
- m_qmlStatus = findViewById(R.id.qmlStatus);
+ m_qmlStatus = findViewById(R.id.qmlStatusText);
m_androidControlsLayout = findViewById(R.id.javaLinear);
- m_box = findViewById(R.id.box);
-
- m_switch = findViewById(R.id.switch1);
+ m_box = findViewById(R.id.qmlColorBox);
+ m_switch = findViewById(R.id.disconnectQmlListenerSwitch);
m_switch.setOnClickListener(view -> switchListener());
- //! [m_qmlView]
- m_qmlView = new QtQuickView(this, "qrc:/qt/qml/qml_in_android_view/main.qml",
- "qml_in_android_view");
- //! [m_qmlView]
+ //! [m_qtQuickView]
+ m_qtQuickView = new QtQuickView(this);
+ //! [m_qtQuickView]
// Set status change listener for m_qmlView
// listener implemented below in OnStatusChanged
//! [setStatusChangeListener]
- m_qmlView.setStatusChangeListener(this);
+ m_mainQmlComponent.setStatusChangeListener(this);
//! [setStatusChangeListener]
+ m_secondQmlComponent.setStatusChangeListener(this);
//! [layoutParams]
ViewGroup.LayoutParams params = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
m_qmlFrameLayout = findViewById(R.id.qmlFrame);
- m_qmlFrameLayout.addView(m_qmlView, params);
+ m_qmlFrameLayout.addView(m_qtQuickView, params);
//! [layoutParams]
- Button button = findViewById(R.id.button);
- button.setOnClickListener(view -> onClickListener());
+ //! [loadComponent]
+ m_qtQuickView.loadComponent(m_mainQmlComponent);
+ //! [loadComponent]
+
+ Button m_changeColorButton = findViewById(R.id.changeQmlColorButton);
+ m_changeColorButton.setOnClickListener(view -> onClickListener());
+ Button m_loadMainQmlButton = findViewById(R.id.loadMainQml);
+ m_loadMainQmlButton.setOnClickListener(view -> loadMainQml());
+ Button m_loadSecondQmlButton = findViewById(R.id.loadSecondQml);
+ m_loadSecondQmlButton.setOnClickListener(view -> loadSecondQml());
+ Button m_rotateQmlGridButton = findViewById(R.id.rotateQmlGridButton);
+ m_rotateQmlGridButton.setOnClickListener(view -> rotateQmlGrid());
// Check target device orientation on launch
handleOrientationChanges();
}
+
//! [onCreate]
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
@@ -113,44 +128,21 @@ public class MainActivity extends AppCompatActivity implements QtQuickView.Statu
m_androidControlsLayout.setLayoutParams(linearLayoutParams);
}
- //! [onStatusChanged]
- @Override
- public void onStatusChanged(int status) {
- Log.i(TAG, "Status of QtQuickView: " + status);
-
- final String qmlStatus = getResources().getString(R.string.qml_view_status)
- + m_statusNames.get(status);
-
- // Show current QML View status in a textview
- m_qmlStatus.setText(qmlStatus);
-
- // Connect signal listener to "onClicked" signal from main.qml
- // addSignalListener returns int which can be used later to identify the listener
- //! [qml signal listener]
- if (status == QtQuickView.STATUS_READY && !m_switch.isChecked()) {
- m_qmlButtonSignalListenerId = m_qmlView.connectSignalListener("onClicked", Object.class,
- (String signal, Object o) -> {
- Log.i(TAG, "QML button clicked");
- m_androidControlsLayout.setBackgroundColor(Color.parseColor(m_colors.getColor()));
- });
-
- }
- //! [qml signal listener]
- }
- //! [onStatusChanged]
//! [onClickListener]
public void onClickListener() {
// Set the QML view root object property "colorStringFormat" value to
// color from Colors.getColor()
- m_qmlView.setProperty("colorStringFormat", m_colors.getColor());
-
- String qmlBackgroundColor = m_qmlView.getProperty("colorStringFormat");
+ m_mainQmlComponent.setColorStringFormat(m_colors.getColor());
+ String qmlBackgroundColor = m_mainQmlComponent.getColorStringFormat();
// Display the QML View background color code
m_getPropertyValueText.setText(qmlBackgroundColor);
// Display the QML View background color in a view
- m_box.setBackgroundColor(Color.parseColor(qmlBackgroundColor));
+ // if qmlBackGroundColor is not null
+ if (qmlBackgroundColor != null) {
+ m_box.setBackgroundColor(Color.parseColor(qmlBackgroundColor));
+ }
}
//! [onClickListener]
@@ -162,16 +154,68 @@ public class MainActivity extends AppCompatActivity implements QtQuickView.Statu
Log.i(TAG, "QML button onClicked signal listener disconnected");
text.setText(R.string.connect_qml_button_signal_listener);
//! [disconnect qml signal listener]
- m_qmlView.disconnectSignalListener(m_qmlButtonSignalListenerId);
+ m_mainQmlComponent.disconnectSignalListener(m_qmlButtonSignalListenerId);
//! [disconnect qml signal listener]
} else {
Log.i(TAG, "QML button onClicked signal listener connected");
text.setText(R.string.disconnect_qml_button_signal_listener);
- m_qmlButtonSignalListenerId = m_qmlView.connectSignalListener("onClicked",
- Object.class, (String t, Object value) -> {
- Log.i(TAG, "QML button clicked");
- m_androidControlsLayout.setBackgroundColor(Color.parseColor(m_colors.getColor()));
- });
+ m_qmlButtonSignalListenerId = m_mainQmlComponent.connectOnClickedListener(
+ (String name, Void v) -> {
+ Log.i(TAG, "QML button clicked");
+ m_androidControlsLayout.setBackgroundColor(Color.parseColor(
+ m_colors.getColor()
+ ));
+ });
+ }
+ }
+
+ //! [onStatusChanged]
+ @Override
+ public void onStatusChanged(QtQmlStatus qtQmlStatus) {
+ Log.i(TAG, "Status of QtQuickView: " + qtQmlStatus);
+
+ final String qmlStatus = getResources().getString(R.string.qml_view_status)
+ + m_statusNames.get(qtQmlStatus);
+
+ // Show current QML View status in a textview
+ m_qmlStatus.setText(qmlStatus);
+
+ // Connect signal listener to "onClicked" signal from main.qml
+ // addSignalListener returns int which can be used later to identify the listener
+ //! [qml signal listener]
+ if (qtQmlStatus == QtQmlStatus.READY && !m_switch.isChecked()) {
+ m_qmlButtonSignalListenerId = m_mainQmlComponent.connectOnClickedListener(
+ (String name, Void v) -> {
+ Log.i(TAG, "QML button clicked");
+ m_androidControlsLayout.setBackgroundColor(Color.parseColor(
+ m_colors.getColor()
+ ));
+ });
+
+ }
+ //! [qml signal listener]
+ }
+ //! [onStatusChanged]
+
+ private void loadSecondQml() {
+ m_qtQuickView.loadComponent(m_secondQmlComponent);
+
+ // Reset box color and color text after component reload
+ m_box.setBackgroundColor(Color.parseColor("#00ffffff"));
+ m_getPropertyValueText.setText("");
+ }
+
+ private void loadMainQml() {
+ m_qtQuickView.loadComponent(m_mainQmlComponent);
+
+ // Reset box color and color text after component reload
+ m_box.setBackgroundColor(Color.parseColor("#00ffffff"));
+ m_getPropertyValueText.setText("");
+ }
+ private void rotateQmlGrid() {
+ Integer previousGridRotation = m_secondQmlComponent.getGridRotation();
+ if (previousGridRotation != null) {
+ m_secondQmlComponent.setGridRotation(previousGridRotation + 45);
}
}
}
diff --git a/examples/platforms/android/qml_in_java_based_android_project/app/src/main/res/layout/activity_main.xml b/examples/platforms/android/qml_in_java_based_android_project/app/src/main/res/layout/activity_main.xml
index 0d55ae643b..52902823c5 100644
--- a/examples/platforms/android/qml_in_java_based_android_project/app/src/main/res/layout/activity_main.xml
+++ b/examples/platforms/android/qml_in_java_based_android_project/app/src/main/res/layout/activity_main.xml
@@ -40,7 +40,7 @@
android:textStyle="bold" />
<TextView
- android:id="@+id/qmlStatus"
+ android:id="@+id/qmlStatusText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
@@ -76,7 +76,7 @@
android:textColor="@color/white" />
<Button
- android:id="@+id/button"
+ android:id="@+id/changeQmlColorButton"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
@@ -103,7 +103,7 @@
android:textColor="@color/white" />
<androidx.appcompat.widget.SwitchCompat
- android:id="@+id/switch1"
+ android:id="@+id/disconnectQmlListenerSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
@@ -121,7 +121,7 @@
<LinearLayout
android:id="@+id/qmlColorLinear"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
@@ -151,14 +151,49 @@
</LinearLayout>
<View
- android:id="@+id/box"
+ android:id="@+id/qmlColorBox"
android:layout_width="100dp"
android:layout_height="50dp"
android:layout_gravity="center_horizontal"
android:background="@android:color/transparent"
android:layout_weight="0"/>
+
</LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_horizontal">
+
+ <Button
+ android:id="@+id/loadSecondQml"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="8dp"
+ android:text="Load Second Qml"
+ android:textSize="14sp"
+ android:layout_marginRight="20dp"/>
+
+ <Button
+ android:id="@+id/loadMainQml"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="8dp"
+ android:text="Load Main Qml"
+ android:textSize="14sp" />
+ </LinearLayout>
+ <Button
+ android:id="@+id/rotateQmlGridButton"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="8dp"
+ android:text="Rotate Qml grid"
+ android:textSize="14sp" />
+
</LinearLayout>
</LinearLayout>
diff --git a/examples/platforms/android/qml_in_kotlin_based_android_project/app/build.gradle b/examples/platforms/android/qml_in_kotlin_based_android_project/app/build.gradle
index be631746b6..18c5756657 100644
--- a/examples/platforms/android/qml_in_kotlin_based_android_project/app/build.gradle
+++ b/examples/platforms/android/qml_in_kotlin_based_android_project/app/build.gradle
@@ -9,7 +9,7 @@ android {
defaultConfig {
applicationId "com.example.qml_in_kotlin_based_android_project"
- minSdk 26
+ minSdk 28
targetSdk 34
versionCode 1
versionName "1.0"
diff --git a/examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt b/examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt
index 4ec1591709..cf2a27035a 100644
--- a/examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt
+++ b/examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/java/com/example/qml_in_kotlin_based_android_project/MainActivity.kt
@@ -5,25 +5,35 @@ import android.graphics.Color
import android.os.Bundle
import android.util.DisplayMetrics
import android.util.Log
+import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import com.example.qml_in_kotlin_based_android_project.databinding.ActivityMainBinding
+import org.qtproject.example.qml_in_android_view.QmlModule.Main
+import org.qtproject.example.qml_in_android_view.QmlModule.Second
+import org.qtproject.qt.android.QtQmlStatus
+import org.qtproject.qt.android.QtQmlStatusChangeListener
import org.qtproject.qt.android.QtQuickView
-class MainActivity : AppCompatActivity(), QtQuickView.StatusChangeListener {
+
+class MainActivity : AppCompatActivity(), QtQmlStatusChangeListener {
private val TAG = "myTag"
private val m_colors: Colors = Colors()
private lateinit var m_binding: ActivityMainBinding
private var m_qmlButtonSignalListenerId = 0
- private var m_qmlView: QtQuickView? = null
+ private var m_qtQuickView: QtQuickView? = null
+ //! [qmlComponent]
+ private var m_mainQmlComponent: Main = Main()
+ //! [qmlComponent]
+ private val m_secondQmlComponent: Second = Second()
private val m_statusNames = hashMapOf(
- QtQuickView.STATUS_READY to "READY",
- QtQuickView.STATUS_LOADING to "LOADING",
- QtQuickView.STATUS_ERROR to "ERROR",
- QtQuickView.STATUS_NULL to "NULL"
+ QtQmlStatus.READY to "READY",
+ QtQmlStatus.LOADING to "LOADING",
+ QtQmlStatus.ERROR to "ERROR",
+ QtQmlStatus.NULL to "NULL"
)
//! [onCreate]
override fun onCreate(savedInstanceState: Bundle?) {
@@ -36,27 +46,31 @@ class MainActivity : AppCompatActivity(), QtQuickView.StatusChangeListener {
m_binding.signalSwitch.setOnClickListener { switchListener() }
- //! [m_qmlView]
- m_qmlView = QtQuickView(
- this, "qrc:/qt/qml/qml_in_android_view/main.qml",
- "qml_in_android_view"
- )
- //! [m_qmlView]
+ //! [m_qtQuickView]
+ m_qtQuickView = QtQuickView(this)
+ //! [m_qtQuickView]
// Set status change listener for m_qmlView
// listener implemented below in OnStatusChanged
//! [setStatusChangeListener]
- m_qmlView!!.setStatusChangeListener(this)
+ m_mainQmlComponent.setStatusChangeListener(this)
//! [setStatusChangeListener]
+ m_secondQmlComponent.setStatusChangeListener(this)
//! [layoutParams]
val params: ViewGroup.LayoutParams = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
)
- m_binding.qmlFrame.addView(m_qmlView, params)
+ m_binding.qmlFrame.addView(m_qtQuickView, params)
//! [layoutParams]
+ //! [loadComponent]
+ m_qtQuickView!!.loadComponent(m_mainQmlComponent)
+ //! [loadComponent]
m_binding.changeColorButton.setOnClickListener { onClickListener() }
+ m_binding.loadMainQml.setOnClickListener { loadMainQml() }
+ m_binding.loadSecondQml.setOnClickListener { loadSecondQml() }
+ m_binding.rotateQmlGridButton.setOnClickListener { rotateQmlGrid() }
// Check target device orientation on launch
handleOrientationChanges()
@@ -91,19 +105,23 @@ class MainActivity : AppCompatActivity(), QtQuickView.StatusChangeListener {
m_binding.qmlFrame.layoutParams = qmlFrameLayoutParams
m_binding.kotlinLinear.layoutParams = linearLayoutParams
}
+
//! [onClickListener]
private fun onClickListener() {
// Set the QML view root object property "colorStringFormat" value to
// color from Colors.getColor()
- m_qmlView!!.setProperty("colorStringFormat", m_colors.getColor())
+ m_mainQmlComponent.colorStringFormat = m_colors.getColor()
- val qmlBackgroundColor = m_qmlView!!.getProperty<String>("colorStringFormat")
+ val qmlBackgroundColor = m_mainQmlComponent.colorStringFormat
// Display the QML View background color code
m_binding.getPropertyValueText.text = qmlBackgroundColor
// Display the QML View background color in a view
- m_binding.colorBox.setBackgroundColor(Color.parseColor(qmlBackgroundColor))
+ // if qmlBackgroundColor is not null
+ if (qmlBackgroundColor != null) {
+ m_binding.colorBox.setBackgroundColor(Color.parseColor(qmlBackgroundColor))
+ }
}
//! [onClickListener]
@@ -114,23 +132,25 @@ class MainActivity : AppCompatActivity(), QtQuickView.StatusChangeListener {
Log.v(TAG, "QML button onClicked signal listener disconnected")
m_binding.switchText.setText(R.string.connect_qml_button_signal_listener)
//! [disconnect qml signal listener]
- m_qmlView!!.disconnectSignalListener(m_qmlButtonSignalListenerId)
+ m_mainQmlComponent.disconnectSignalListener(m_qmlButtonSignalListenerId)
//! [disconnect qml signal listener]
} else {
Log.v(TAG, "QML button onClicked signal listener connected")
m_binding.switchText.setText(R.string.disconnect_qml_button_signal_listener)
- m_qmlButtonSignalListenerId = m_qmlView!!.connectSignalListener<Any>(
- "onClicked",
- Any::class.java
- ) { t: String?, value: Any? ->
- Log.i(TAG, "QML button clicked")
- m_binding.kotlinLinear.setBackgroundColor(Color.parseColor(m_colors.getColor()))
- }
+ m_qmlButtonSignalListenerId =
+ m_mainQmlComponent.connectOnClickedListener { _: String, _: Void? ->
+ Log.i(TAG, "QML button clicked")
+ m_binding.kotlinLinear.setBackgroundColor(
+ Color.parseColor(
+ m_colors.getColor()
+ )
+ )
+ }
}
}
//! [onStatusChanged]
- override fun onStatusChanged(status: Int) {
+ override fun onStatusChanged(status: QtQmlStatus?) {
Log.v(TAG, "Status of QtQuickView: $status")
val qmlStatus = (resources.getString(R.string.qml_view_status)
@@ -142,15 +162,41 @@ class MainActivity : AppCompatActivity(), QtQuickView.StatusChangeListener {
// Connect signal listener to "onClicked" signal from main.qml
// addSignalListener returns int which can be used later to identify the listener
//! [qml signal listener]
- if (status == QtQuickView.STATUS_READY && !m_binding.signalSwitch.isChecked) {
- m_qmlButtonSignalListenerId = m_qmlView!!.connectSignalListener(
- "onClicked", Any::class.java
- ) { _: String?, _: Any? ->
- Log.v(TAG, "QML button clicked")
- m_binding.kotlinLinear.setBackgroundColor(Color.parseColor(m_colors.getColor()))
- }
+ if (status == QtQmlStatus.READY && !m_binding.signalSwitch.isChecked) {
+ m_qmlButtonSignalListenerId =
+ m_mainQmlComponent.connectOnClickedListener { _: String, _: Void? ->
+ Log.i(TAG, "QML button clicked")
+ m_binding.kotlinLinear.setBackgroundColor(
+ Color.parseColor(
+ m_colors.getColor()
+ )
+ )
+ }
}
//! [qml signal listener]
}
//! [onStatusChanged]
+
+ private fun loadSecondQml() {
+ m_qtQuickView!!.loadComponent(m_secondQmlComponent)
+
+ // Reset box color and color text after component reload
+ m_binding.colorBox.setBackgroundColor(Color.parseColor("#00ffffff"))
+ m_binding.getPropertyValueText.text = ""
+ }
+
+ private fun loadMainQml() {
+ m_qtQuickView!!.loadComponent(m_mainQmlComponent)
+
+ // Reset box color and color text after component reload
+ m_binding.colorBox.setBackgroundColor(Color.parseColor("#00ffffff"))
+ m_binding.getPropertyValueText.text = ""
+ }
+
+ private fun rotateQmlGrid() {
+ val previousGridRotation = m_secondQmlComponent.gridRotation
+ if (previousGridRotation != null) {
+ m_secondQmlComponent.gridRotation = previousGridRotation + 45
+ }
+ }
}
diff --git a/examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/res/layout/activity_main.xml b/examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/res/layout/activity_main.xml
index 03f01fdd25..b08cebf9c0 100644
--- a/examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/res/layout/activity_main.xml
+++ b/examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/res/layout/activity_main.xml
@@ -121,7 +121,7 @@
<LinearLayout
android:id="@+id/qmlColorLinear"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
@@ -159,6 +159,40 @@
android:layout_weight="0"/>
</LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_horizontal">
+
+ <Button
+ android:id="@+id/loadSecondQml"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="8dp"
+ android:text="@string/load_second_qml"
+ android:textSize="14sp"
+ android:layout_marginRight="20dp"/>
+
+ <Button
+ android:id="@+id/loadMainQml"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="8dp"
+ android:text="@string/load_main_qml"
+ android:textSize="14sp" />
+ </LinearLayout>
+ <Button
+ android:id="@+id/rotateQmlGridButton"
+ android:layout_width="100dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="8dp"
+ android:text="@string/rotate_qml_grid"
+ android:textSize="14sp" />
+
</LinearLayout>
</LinearLayout>
diff --git a/examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/res/values/strings.xml b/examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/res/values/strings.xml
index 12661a6334..b08e6c37fa 100644
--- a/examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/res/values/strings.xml
+++ b/examples/platforms/android/qml_in_kotlin_based_android_project/app/src/main/res/values/strings.xml
@@ -9,4 +9,7 @@
<string name="off">Off</string>
<string name="qml_view_status">QML view status: </string>
<string name="qml_view_background_color">QML view background color:</string>
+ <string name="load_main_qml">Load Main Qml</string>
+ <string name="load_second_qml">Load Second Qml</string>
+ <string name="rotate_qml_grid">Rotate Qml grid</string>
</resources>
diff --git a/examples/quick/quickshapes/shapes/CMakeLists.txt b/examples/quick/quickshapes/shapes/CMakeLists.txt
index 5036f1a37e..4fcb118d81 100644
--- a/examples/quick/quickshapes/shapes/CMakeLists.txt
+++ b/examples/quick/quickshapes/shapes/CMakeLists.txt
@@ -52,6 +52,9 @@ qt_add_qml_module(shapesexample
"tapableTriangle.qml"
"tiger.qml"
"zoomtiger.qml"
+ "fillTransform.qml"
+ "rectangle.qml"
+ "fillItem.qml"
)
install(TARGETS shapesexample
diff --git a/examples/quick/quickshapes/shapes/fillItem.qml b/examples/quick/quickshapes/shapes/fillItem.qml
new file mode 100644
index 0000000000..84fef37eeb
--- /dev/null
+++ b/examples/quick/quickshapes/shapes/fillItem.qml
@@ -0,0 +1,50 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Shapes
+import shared
+
+Rectangle {
+ color: "lightGray"
+ width: 256
+ height: 256
+
+ Image {
+ id: image
+ source: Images.qtLogo
+ visible: false
+ }
+
+ Shape {
+ id: shape
+ anchors.centerIn: parent
+ width: 200
+ height: 100
+
+ ShapePath {
+ strokeColor: "black"
+ strokeWidth: 1
+ fillItem: image
+ fillTransform: PlanarTransform.fromScale(0.5, 0.5)
+ startX: shape.width / 2 - 40
+ startY: shape.height / 2 - 40
+
+ PathArc {
+ x: shape.width / 2 + 40
+ y: shape.height / 2 + 40
+ radiusX: 40
+ radiusY: 40
+ useLargeArc: true
+ }
+
+ PathArc {
+ x: shape.width / 2 - 40
+ y: shape.height / 2 - 40
+ radiusX: 40
+ radiusY: 40
+ useLargeArc: true
+ }
+ }
+ }
+}
diff --git a/examples/quick/quickshapes/shapes/fillTransform.qml b/examples/quick/quickshapes/shapes/fillTransform.qml
new file mode 100644
index 0000000000..f09a5d63e1
--- /dev/null
+++ b/examples/quick/quickshapes/shapes/fillTransform.qml
@@ -0,0 +1,46 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Shapes
+
+Rectangle {
+ color: "lightGray"
+ width: 256
+ height: 256
+
+ Shape {
+ anchors.centerIn: parent
+ width: 200
+ height: 100
+
+ ShapePath {
+ id: path1
+ fillGradient: RadialGradient {
+ id: grad
+ centerX: path1.startX + 100
+ centerY: path1.startY + 50
+ centerRadius: 50
+ focalX: centerX
+ focalY: centerY
+ GradientStop { position: 0.0; color: "blue" }
+ GradientStop { position: 0.5; color: "cyan" }
+ GradientStop { position: 1.0; color: "blue" }
+ }
+
+ property real fillScale: 1
+ NumberAnimation on fillScale {
+ running: true
+ loops: Animation.Infinite
+ from: 1
+ to: 5
+ duration: 3000
+ easing.type: Easing.InQuad
+ }
+
+ fillTransform: PlanarTransform.fromScale(fillScale, 1, grad.centerX, grad.centerY)
+
+ PathRectangle { width: 200; height: 100 }
+ }
+ }
+}
diff --git a/examples/quick/quickshapes/shapes/rectangle.qml b/examples/quick/quickshapes/shapes/rectangle.qml
new file mode 100644
index 0000000000..afac8850ff
--- /dev/null
+++ b/examples/quick/quickshapes/shapes/rectangle.qml
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Shapes
+
+Rectangle {
+ color: "lightGray"
+ width: 256
+ height: 256
+
+ Shape {
+ id: myShape
+ anchors.fill: parent
+
+ ShapePath {
+ id: myPath
+ strokeColor: "green"
+ strokeWidth: myShape.width / 25
+ joinStyle: ShapePath.MiterJoin
+ fillGradient: LinearGradient {
+ x2: myShape.width
+ y2: x2
+ GradientStop { position: 0.1; color: "yellow" }
+ GradientStop { position: 0.45; color: "lightyellow" }
+ GradientStop { position: 0.7; color: "yellow" }
+ }
+
+ property real animRadius: 0
+ SequentialAnimation on animRadius {
+ loops: Animation.Infinite
+ NumberAnimation {
+ from: 0
+ to: 100
+ duration: 3000
+ }
+ NumberAnimation {
+ from: 100
+ to: 0
+ duration: 3000
+ }
+ PauseAnimation {
+ duration: 1000
+ }
+ }
+
+ PathRectangle {
+ x: myShape.width / 5
+ y: x
+ width: myShape.width - 2 * x
+ height: width
+ topLeftRadius: myPath.animRadius
+ bottomRightRadius: myPath.animRadius
+ }
+ }
+ }
+}
diff --git a/examples/quick/quickshapes/shapes/shapegallery.qml b/examples/quick/quickshapes/shapes/shapegallery.qml
index 74059b8208..2e79e4515b 100644
--- a/examples/quick/quickshapes/shapes/shapegallery.qml
+++ b/examples/quick/quickshapes/shapes/shapegallery.qml
@@ -146,6 +146,18 @@ Rectangle {
name: qsTr("Text")
shapeUrl: "text.qml"
}
+ ListElement {
+ name: qsTr("Fill transform")
+ shapeUrl: "fillTransform.qml"
+ }
+ ListElement {
+ name: qsTr("Shape Rectangle")
+ shapeUrl: "rectangle.qml"
+ }
+ ListElement {
+ name: qsTr("Fill item")
+ shapeUrl: "fillItem.qml"
+ }
}
}
}
diff --git a/examples/quick/quickshapes/shapes/shapes.qrc b/examples/quick/quickshapes/shapes/shapes.qrc
index 413816dba2..afbc7fcf5e 100644
--- a/examples/quick/quickshapes/shapes/shapes.qrc
+++ b/examples/quick/quickshapes/shapes/shapes.qrc
@@ -24,5 +24,7 @@
<file>tigerLoader.qml</file>
<file>text.qml</file>
<file>zoomtiger.qml</file>
+ <file>fillTransform.qml</file>
+ <file>rectangle.qml</file>
</qresource>
</RCC>
diff --git a/examples/quick/scenegraph/graph/shaders/noisy.frag b/examples/quick/scenegraph/graph/shaders/noisy.frag
index 0b7cb1306b..0f13b83fd4 100644
--- a/examples/quick/scenegraph/graph/shaders/noisy.frag
+++ b/examples/quick/scenegraph/graph/shaders/noisy.frag
@@ -11,7 +11,7 @@ layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
vec4 color;
- vec2 textureSize;
+ vec2 texCoordScale;
float qt_Opacity;
};
diff --git a/examples/quick/scenegraph/graph/shaders/noisy.frag.qsb b/examples/quick/scenegraph/graph/shaders/noisy.frag.qsb
index 1a49e93cf3..dd1739b1fe 100644
--- a/examples/quick/scenegraph/graph/shaders/noisy.frag.qsb
+++ b/examples/quick/scenegraph/graph/shaders/noisy.frag.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/graph/shaders/noisy.vert b/examples/quick/scenegraph/graph/shaders/noisy.vert
index 5728f2a02f..057f1c8d16 100644
--- a/examples/quick/scenegraph/graph/shaders/noisy.vert
+++ b/examples/quick/scenegraph/graph/shaders/noisy.vert
@@ -9,7 +9,7 @@ layout(location = 1) out vec2 vShadeCoord;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
vec4 color;
- vec2 textureSize;
+ vec2 texCoordScale;
float qt_Opacity;
};
@@ -17,6 +17,6 @@ out gl_PerVertex { vec4 gl_Position; };
void main() {
gl_Position = qt_Matrix * aVertex;
- vTexCoord = aVertex.xy * textureSize;
+ vTexCoord = aVertex.xy * texCoordScale;
vShadeCoord = aTexCoord;
}
diff --git a/examples/quick/scenegraph/graph/shaders/noisy.vert.qsb b/examples/quick/scenegraph/graph/shaders/noisy.vert.qsb
index ce2a828ead..9de384e3a6 100644
--- a/examples/quick/scenegraph/graph/shaders/noisy.vert.qsb
+++ b/examples/quick/scenegraph/graph/shaders/noisy.vert.qsb
Binary files differ
diff --git a/examples/quick/scenegraph/openglunderqml/squircle.cpp b/examples/quick/scenegraph/openglunderqml/squircle.cpp
index 13f3075a28..98a004ee80 100644
--- a/examples/quick/scenegraph/openglunderqml/squircle.cpp
+++ b/examples/quick/scenegraph/openglunderqml/squircle.cpp
@@ -94,6 +94,15 @@ void SquircleRenderer::init()
initializeOpenGLFunctions();
+ const float values[] = { -1, -1, 1, -1, -1, 1, 1, 1 };
+
+ m_vbo.create();
+ m_vbo.bind();
+ m_vbo.allocate(values, sizeof(values));
+
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
+
m_program = new QOpenGLShaderProgram();
m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex,
"attribute highp vec4 vertices;"
@@ -125,23 +134,12 @@ void SquircleRenderer::paint()
// OpenGL directly.
m_window->beginExternalCommands();
+ m_vbo.bind();
m_program->bind();
+ m_program->setUniformValue("t", (float)m_t);
- m_program->enableAttributeArray(0);
-
- float values[] = {
- -1, -1,
- 1, -1,
- -1, 1,
- 1, 1
- };
-
- // This example relies on (deprecated) client-side pointers for the vertex
- // input. Therefore, we have to make sure no vertex buffer is bound.
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- m_program->setAttributeArray(0, GL_FLOAT, values, 2);
- m_program->setUniformValue("t", (float) m_t);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
glViewport(0, 0, m_viewportSize.width(), m_viewportSize.height());
@@ -152,7 +150,7 @@ void SquircleRenderer::paint()
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- m_program->disableAttributeArray(0);
+ glDisableVertexAttribArray(0);
m_program->release();
m_window->endExternalCommands();
diff --git a/examples/quick/scenegraph/openglunderqml/squircle.h b/examples/quick/scenegraph/openglunderqml/squircle.h
index 2112d658b0..e59e7882c8 100644
--- a/examples/quick/scenegraph/openglunderqml/squircle.h
+++ b/examples/quick/scenegraph/openglunderqml/squircle.h
@@ -8,6 +8,7 @@
#include <QtQuick/QQuickWindow>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>
+#include <QOpenGLBuffer>
@@ -31,6 +32,7 @@ private:
qreal m_t = 0.0;
QOpenGLShaderProgram *m_program = nullptr;
QQuickWindow *m_window = nullptr;
+ QOpenGLBuffer m_vbo;
};
//! [1]
diff --git a/examples/quickcontrols/spreadsheets/CMakeLists.txt b/examples/quickcontrols/spreadsheets/CMakeLists.txt
new file mode 100644
index 0000000000..de15fee0d1
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/CMakeLists.txt
@@ -0,0 +1,46 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(SpreadsheetsExample VERSION 1.0 LANGUAGES CXX)
+
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(Qt6 6.8 REQUIRED COMPONENTS Gui Qml)
+
+qt_standard_project_setup(REQUIRES 6.8)
+
+add_subdirectory(Spreadsheets)
+
+qt_add_executable(${PROJECT_NAME} WIN32
+ main.cpp
+)
+
+target_link_libraries(${PROJECT_NAME} PRIVATE
+ Qt6::Gui
+ Qt6::Qml
+ Spreadsheets
+)
+
+qt_add_resources(${PROJECT_NAME} "spareadsheet_icon"
+ PREFIX "/qt/examples/spreadsheet/icons"
+ FILES spreadsheet.svg
+)
+
+# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
+# If you are developing for iOS or macOS you should consider setting an
+# explicit, fixed bundle identifier manually though.
+set_target_properties(${PROJECT_NAME} PROPERTIES
+# MACOSX_BUNDLE_GUI_IDENTIFIER "io.qt.examples.Spreadsheets"
+ MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
+ MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
+ MACOSX_BUNDLE TRUE
+ WIN32_EXECUTABLE TRUE
+)
+
+# include(GNUInstallDirs)
+install(TARGETS ${PROJECT_NAME}
+ BUNDLE DESTINATION .
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/CMakeLists.txt b/examples/quickcontrols/spreadsheets/Spreadsheets/CMakeLists.txt
new file mode 100644
index 0000000000..9c2f66c0a0
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/CMakeLists.txt
@@ -0,0 +1,47 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(Spreadsheets LANGUAGES CXX)
+
+find_package(Qt6 6.8 REQUIRED COMPONENTS Core Quick Qml)
+qt_standard_project_setup(REQUIRES 6.8)
+
+qt_add_qml_module(${PROJECT_NAME}
+ URI Spreadsheets
+ VERSION 1.0
+ QML_FILES
+ Main.qml
+ TableCell.qml
+ HeaderToolBar.qml
+ HelpDialog.qml
+ SOURCES
+ datamodel.h datamodel.cpp
+ spreadcell.h spreadcell.cpp
+ spreadformula.h spreadformula.cpp
+ spreadkey.h
+ spreadmimedataprovider.h spreadmimedataprovider.cpp
+ spreadmodel.h spreadmodel.cpp
+ spreadrole.h
+ RESOURCES
+ icons/insert_column_left.svg
+ icons/insert_column_right.svg
+ icons/insert_row_above.svg
+ icons/insert_row_below.svg
+ icons/remove_column.svg
+ icons/remove_row.svg
+ icons/pan.svg
+ icons/paste.svg
+ icons/copy.svg
+ icons/cut.svg
+ icons/help.svg
+ icons/hide.svg
+ icons/show.svg
+ icons/reset_reordering.svg
+)
+
+target_link_libraries(${PROJECT_NAME} PRIVATE
+ Qt6::Core
+ Qt6::Quick
+ Qt6::Qml
+)
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/HeaderToolBar.qml b/examples/quickcontrols/spreadsheets/Spreadsheets/HeaderToolBar.qml
new file mode 100644
index 0000000000..d3f6f26c77
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/HeaderToolBar.qml
@@ -0,0 +1,96 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+Item {
+ id: root
+ implicitHeight: 40
+ implicitWidth: 40
+
+ property alias panEnabled: panButton.checked
+ readonly property int __icon_size: 20
+
+ signal helpRequested()
+ signal cutRequested()
+ signal copyRequested()
+ signal pasteRequested()
+
+ ToolBar {
+ anchors.fill: parent
+
+ RowLayout {
+ anchors.fill: parent
+
+ ToolButton {
+ id: helpButton
+ icon.source: "icons/help.svg"
+ icon.width: root.__icon_size
+ icon.height: root.__icon_size
+ icon.color: palette.text
+ onClicked: helpRequested()
+ ToolTip {
+ text: qsTr("Help")
+ visible: helpButton.hovered
+ }
+ }
+
+ ToolButton {
+ id: panButton
+ icon.source: "icons/pan.svg"
+ icon.color: palette.text
+ icon.width: root.__icon_size
+ icon.height: root.__icon_size
+ flat: true
+ checkable: true
+ ToolTip {
+ text: qsTr("Pan")
+ visible: panButton.hovered
+ }
+ }
+
+ ToolButton {
+ id: cutButton
+ icon.source: "icons/cut.svg"
+ icon.color: palette.text
+ icon.width: root.__icon_size
+ icon.height: root.__icon_size
+ onClicked: cutRequested()
+ ToolTip {
+ text: qsTr("Cut")
+ visible: cutButton.hovered
+ }
+ }
+
+ ToolButton {
+ id: copyButton
+ icon.source: "icons/copy.svg"
+ icon.color: palette.text
+ icon.width: root.__icon_size
+ icon.height: root.__icon_size
+ onClicked: copyRequested()
+ ToolTip {
+ text: qsTr("Copy")
+ visible: copyButton.hovered
+ }
+ }
+
+ ToolButton {
+ id: pasteButton
+ icon.source: "icons/paste.svg"
+ icon.color: palette.text
+ icon.width: root.__icon_size
+ icon.height: root.__icon_size
+ onClicked: pasteRequested()
+ ToolTip {
+ text: qsTr("Paste")
+ visible: pasteButton.hovered
+ }
+ }
+
+ Item { Layout.fillWidth: true }
+ }
+ }
+}
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/HelpDialog.qml b/examples/quickcontrols/spreadsheets/Spreadsheets/HelpDialog.qml
new file mode 100644
index 0000000000..e98fbd8f2e
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/HelpDialog.qml
@@ -0,0 +1,111 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+Dialog {
+ id: root
+ modal: true
+ standardButtons: Dialog.Ok
+
+ component SectionHelpInfo: Item {
+ property alias sectionText: section.text
+ property alias sectionDescription: sectionDesc.text
+
+ RowLayout {
+ anchors.fill: parent
+ anchors.leftMargin: 20
+
+ Item {
+ implicitWidth: 40
+ Layout.fillHeight: true
+
+ Label {
+ id: section
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+
+ Rectangle {
+ implicitWidth: 90
+ color: palette.base
+ border.width: 1
+ border.color: Qt.styleHints.colorScheme === Qt.Light ? palette.dark : palette.light
+ Layout.fillHeight: true
+
+ Label {
+ id: sectionDesc
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+ }
+ }
+
+ contentItem: ColumnLayout {
+ spacing: 10
+
+ Item {
+ Layout.topMargin: 20
+ Layout.leftMargin: 20
+ Layout.rightMargin: 20
+ implicitWidth: infoLabel.width
+ implicitHeight: infoLabel.height
+
+ Label {
+ id: infoLabel
+ text: qsTr("A formula starts with `=` follows with the operator and arguments.\n" +
+ "Formula could be")
+ }
+ }
+
+ SectionHelpInfo {
+ implicitHeight: 30
+ Layout.fillWidth: true
+ Layout.leftMargin: 40
+ sectionText: "Cell assignment"
+ sectionDescription: "=A1"
+ }
+
+ SectionHelpInfo {
+ implicitHeight: 30
+ Layout.fillWidth: true
+ Layout.leftMargin: 40
+ sectionText: "Addition"
+ sectionDescription: "=A1+A2"
+ }
+
+ SectionHelpInfo {
+ implicitHeight: 30
+ Layout.fillWidth: true
+ Layout.leftMargin: 40
+ sectionText: "Subtraction"
+ sectionDescription: "=A1-A2"
+ }
+
+ SectionHelpInfo {
+ implicitHeight: 30
+ Layout.fillWidth: true
+ Layout.leftMargin: 40
+ sectionText: "Division"
+ sectionDescription: "=A1/A2"
+ }
+
+ SectionHelpInfo {
+ implicitHeight: 30
+ Layout.fillWidth: true
+ Layout.leftMargin: 40
+ sectionText: "Multiplication"
+ sectionDescription: "=A1*A2"
+ }
+
+ SectionHelpInfo {
+ implicitHeight: 30
+ Layout.fillWidth: true
+ Layout.leftMargin: 40
+ sectionText: "Summation"
+ sectionDescription: "=SUM A1:A2"
+ }
+ }
+}
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/Main.qml b/examples/quickcontrols/spreadsheets/Spreadsheets/Main.qml
new file mode 100644
index 0000000000..8bd748067e
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/Main.qml
@@ -0,0 +1,846 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import Qt.labs.qmlmodels
+
+import Spreadsheets
+
+ApplicationWindow {
+ width: 960
+ height: 720
+ visible: true
+ title: qsTr("Spreadsheets")
+
+ header: HeaderToolBar {
+ id: toolbar
+ panEnabled: false
+ onHelpRequested: helpDialog.open()
+ onPasteRequested: tableView.pasteFromClipboard()
+ onCopyRequested: tableView.copyToClipboard()
+ onCutRequested: tableView.cutToClipboard()
+ }
+
+ background: Rectangle {
+ // to make contrast with the cells of the TableView,
+ // HorizontalHeaderView and VerticalHeaderView
+ color: Qt.styleHints.colorScheme === Qt.Light ? palette.dark : palette.light
+ }
+
+ GridLayout {
+ id: gridlayout
+ anchors.fill: parent
+ anchors.margins: 4
+ columns: 2
+ rows: 2
+ columnSpacing: 3
+ rowSpacing: 3
+
+ HorizontalHeaderView {
+ id: horizontalHeaderView
+ Layout.row: 0
+ Layout.column: 1
+ Layout.fillWidth: true
+ implicitHeight: 36
+ clip: true
+ interactive: toolbar.panEnabled
+ syncView: tableView
+
+ selectionModel: HeaderSelectionModel {
+ id: horizontalHeaderSelectionModel
+ selectionModel: selectionModel
+ orientation: Qt.Horizontal
+ }
+
+ movableColumns: true
+ onColumnMoved: (index, old_column, new_column) => model.mapColumn(index, new_column)
+
+ delegate: Rectangle {
+ id: horizontalHeaderDelegate
+
+ required property var index
+ required property bool selected
+ required property bool containsDrag
+ readonly property real cellPadding: 8
+ readonly property bool containsMenu: columnMenu.column === column
+
+ implicitWidth: horizontalTitle.implicitWidth + (cellPadding * 2)
+ implicitHeight: Math.max(horizontalHeaderView.height,
+ horizontalTitle.implicitHeight + (cellPadding * 2))
+ border {
+ width: containsDrag || containsMenu ? 1 : 0
+ color: palette.highlight
+ }
+ color: selected ? palette.highlight : palette.button
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Qt.styleHints.colorScheme === Qt.Light ? horizontalHeaderDelegate.color
+ : Qt.lighter(horizontalHeaderDelegate.color, 1.3)
+ }
+ GradientStop {
+ position: 1
+ color: Qt.styleHints.colorScheme === Qt.Light ? Qt.darker(horizontalHeaderDelegate.color, 1.3)
+ : horizontalHeaderDelegate.color
+ }
+ }
+
+ Label {
+ id: horizontalTitle
+ anchors.centerIn: parent
+ text: model.columnName
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ anchors.leftMargin: horizontalHeaderDelegate.cellPadding / 2
+ anchors.rightMargin: horizontalHeaderDelegate.cellPadding / 2
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+
+ onPressed: function(event) {
+ if (event.modifiers === Qt.AltModifier) {
+ event.accepted = false
+ return
+ }
+ }
+
+ onClicked: function(event) {
+ switch (event.button) {
+ case Qt.LeftButton:
+ if (event.modifiers & Qt.ControlModifier)
+ selectionModel.toggleColumn(index)
+ else
+ selectionModel.selectColumn(index)
+ break
+ case Qt.RightButton:
+ columnMenu.column = index
+ const menu_pos = mapToItem(horizontalHeaderView, -anchors.margins, height + anchors.margins)
+ columnMenu.popup(menu_pos)
+ break
+ }
+ }
+ }
+ }
+ Menu {
+ id: columnMenu
+
+ property int column: -1
+
+ onOpened: {
+ horizontalHeaderSelectionModel.setCurrent(column)
+ }
+
+ onClosed: {
+ horizontalHeaderSelectionModel.setCurrent()
+ column = -1
+ }
+
+ MenuItem {
+ text: qsTr("Insert 1 column left")
+ icon {
+ source: "icons/insert_column_left.svg"
+ color: palette.highlightedText
+ }
+
+ onClicked: {
+ if (columnMenu.column < 0)
+ return
+ SpreadModel.insertColumn(columnMenu.column)
+ }
+ }
+
+ MenuItem {
+ text: qsTr("Insert 1 column right")
+ icon {
+ source: "icons/insert_column_right.svg"
+ color: palette.highlightedText
+ }
+
+ onClicked: {
+ if (columnMenu.column < 0)
+ return
+ SpreadModel.insertColumn(columnMenu.column + 1)
+ }
+ }
+
+ MenuItem {
+ text: selectionModel.hasSelection ? qsTr("Remove selected columns")
+ : qsTr("Remove column")
+ icon {
+ source: "icons/remove_column.svg"
+ color: palette.text
+ }
+
+ onClicked: {
+ if (selectionModel.hasSelection)
+ SpreadModel.removeColumns(selectionModel.selectedColumns())
+ else if (columnMenu.column >= 0)
+ SpreadModel.removeColumn(columnMenu.column)
+ }
+ }
+
+ MenuItem {
+ text: selectionModel.hasSelection ? qsTr("Hide selected columns")
+ : qsTr("Hide column")
+ icon {
+ source: "icons/hide.svg"
+ color: palette.text
+ }
+
+ onClicked: {
+ if (selectionModel.hasSelection) {
+ let columns = selectionModel.selectedColumns()
+ columns.sort(function(lhs, rhs){ return rhs.column - lhs.column })
+ for (let i in columns)
+ tableView.hideColumn(columns[i].column)
+ selectionModel.clearSelection()
+ } else {
+ tableView.hideColumn(columnMenu.column)
+ }
+ }
+ }
+
+ MenuItem {
+ text: qsTr("Show hidden column(s)")
+ icon {
+ source: "icons/show.svg"
+ color: palette.text
+ }
+
+ enabled: tableView.hiddenColumnCount
+
+ onClicked: {
+ tableView.showHiddenColumns()
+ selectionModel.clearSelection()
+ }
+ }
+
+ MenuItem {
+ text: qsTr("Reset column reordering")
+ icon {
+ source: "icons/reset_reordering.svg"
+ color: palette.text
+ }
+
+ onClicked: tableView.resetColumnReordering()
+ }
+ }
+ }
+
+ VerticalHeaderView {
+ id: verticalHeaderView
+
+ Layout.fillHeight: true
+ implicitWidth: 50
+ clip: true
+ syncView: tableView
+ interactive: toolbar.panEnabled
+ movableRows: true
+
+ selectionModel: HeaderSelectionModel {
+ id: verticalHeaderSelectionModel
+ selectionModel: selectionModel
+ orientation: Qt.Vertical
+ }
+
+ onRowMoved: (index, old_row, new_row) => model.mapRow(index, new_row)
+
+ delegate: Rectangle {
+ id: verticalHeaderDelegate
+
+ required property var index
+ required property bool selected
+ required property bool current
+ required property bool containsDrag
+ readonly property real cellPadding: 8
+
+ implicitHeight: verticalTitle.implicitHeight + (cellPadding * 2)
+ implicitWidth: Math.max(verticalHeaderView.width,
+ verticalTitle.implicitWidth + (cellPadding * 2))
+
+ border {
+ width: containsDrag || current ? 1 : 0
+ color: palette.highlight
+ }
+
+ color: selected ? palette.highlight : palette.button
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Qt.styleHints.colorScheme === Qt.Light ? verticalHeaderDelegate.color
+ : Qt.lighter(verticalHeaderDelegate.color, 1.3)
+ }
+ GradientStop {
+ position: 1
+ color: Qt.styleHints.colorScheme === Qt.Light ? Qt.darker(verticalHeaderDelegate.color, 1.3)
+ : verticalHeaderDelegate.color
+ }
+ }
+
+ Label {
+ id: verticalTitle
+ anchors.centerIn: parent
+ text: model.rowName
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ anchors.topMargin: verticalHeaderDelegate.cellPadding / 2
+ anchors.bottomMargin: verticalHeaderDelegate.cellPadding / 2
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+
+ onPressed: function(event) {
+ if (event.modifiers === Qt.AltModifier) {
+ event.accepted = false
+ return
+ }
+ }
+
+ onClicked: function(event) {
+ switch (event.button) {
+ case Qt.LeftButton:
+ if (event.modifiers & Qt.ControlModifier)
+ selectionModel.toggleRow(index)
+ else
+ selectionModel.selectRow(index)
+ break
+ case Qt.RightButton:
+ rowMenu.row = index
+ const menu_pos = mapToItem(verticalHeaderView, width + anchors.margins, -anchors.margins)
+ rowMenu.popup(menu_pos)
+ break
+ }
+ }
+ }
+ }
+ Menu {
+ id: rowMenu
+
+ property int row: -1
+
+ onOpened: {
+ verticalHeaderSelectionModel.setCurrent(row)
+ }
+
+ onClosed: {
+ verticalHeaderSelectionModel.setCurrent()
+ row = -1
+ }
+
+ MenuItem {
+ text: qsTr("Insert 1 row above")
+ icon {
+ source: "icons/insert_row_above.svg"
+ color: palette.highlightedText
+ }
+
+ onClicked: {
+ if (rowMenu.row < 0)
+ return
+ SpreadModel.insertRow(rowMenu.row)
+ }
+ }
+
+ MenuItem {
+ text: qsTr("Insert 1 row bellow")
+ icon {
+ source: "icons/insert_row_below.svg"
+ color: palette.text
+ }
+
+ onClicked: {
+ if (rowMenu.row < 0)
+ return
+ SpreadModel.insertRow(rowMenu.row + 1)
+ }
+ }
+
+ MenuItem {
+ text: selectionModel.hasSelection ? qsTr("Remove selected rows")
+ : qsTr("Remove row")
+ icon {
+ source: "icons/remove_row.svg"
+ color: palette.text
+ }
+
+ onClicked: {
+ if (selectionModel.hasSelection)
+ SpreadModel.removeRows(selectionModel.selectedRows())
+ else if (rowMenu.row >= 0)
+ SpreadModel.removeRow(rowMenu.row)
+ }
+ }
+
+ MenuItem {
+ text: selectionModel.hasSelection ? qsTr("Hide selected rows")
+ : qsTr("Hide row")
+ icon {
+ source: "icons/hide.svg"
+ color: palette.text
+ }
+
+ onClicked: {
+ if (selectionModel.hasSelection) {
+ let rows = selectionModel.selectedRows()
+ rows.sort(function(lhs, rhs){ return rhs.row - lhs.row })
+ for (let i in rows)
+ tableView.hideRow(rows[i].row)
+ selectionModel.clearSelection()
+ } else {
+ tableView.hideRow(rowMenu.row)
+ }
+ }
+ }
+
+ MenuItem {
+ text: qsTr("Show hidden row(s)")
+ icon {
+ source: "icons/show.svg"
+ color: palette.text
+ }
+ enabled: tableView.hiddenRowCount
+
+ onClicked: {
+ tableView.showHiddenRows()
+ selectionModel.clearSelection()
+ }
+ }
+
+ MenuItem {
+ text: qsTr("Reset row reordering")
+ icon {
+ source: "icons/reset_reordering.svg"
+ color: palette.text
+ }
+
+ onClicked: tableView.resetRowReordering()
+ }
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ TableView {
+ id: tableView
+
+ property int hiddenColumnCount: 0
+ property int hiddenRowCount: 0
+
+ anchors.fill: parent
+ clip: true
+ columnSpacing: 2
+ rowSpacing: 2
+ boundsBehavior: Flickable.StopAtBounds
+ selectionBehavior: TableView.SelectCells
+ selectionMode: TableView.ExtendedSelection
+ selectionModel: selectionModel
+ interactive: toolbar.panEnabled
+ model: SpreadModel
+
+ function showHiddenColumns()
+ {
+ for (let column = 0; column < columns; ++column) {
+ if (explicitColumnWidth(column) === 0)
+ setColumnWidth(column, -1)
+ }
+ hiddenColumnCount = 0
+ }
+
+ function hideColumn(column)
+ {
+ if (column < 0)
+ return
+ setColumnWidth(column, 0)
+ ++hiddenColumnCount
+ }
+
+ function showHiddenRows()
+ {
+ for (let row = 0; row < rows; ++row) {
+ if (explicitRowHeight(row) === 0)
+ setRowHeight(row, -1)
+ }
+ hiddenRowCount = 0
+ }
+
+ function hideRow(row)
+ {
+ if (row < 0)
+ return
+ setRowHeight(row, 0)
+ ++hiddenRowCount
+ }
+
+ function copyToClipboard()
+ {
+ mimeDataProvider.reset()
+ if (selectionModel.hasSelection) {
+ const source_index = selectionModel.selectedIndexes[0]
+ mimeDataProvider.sourceCell = cellAtIndex(source_index)
+ mimeDataProvider.loadSelectedData()
+ } else {
+ const current_index = selectionModel.currentIndex
+ const current_cell = cellAtIndex(current_index)
+ mimeDataProvider.sourceCell = current_cell
+ mimeDataProvider.loadDataFromModel(current_cell, current_index, model)
+ }
+ }
+
+ function cutToClipboard()
+ {
+ mimeDataProvider.reset()
+ if (selectionModel.hasSelection) {
+ const source_index = selectionModel.selectedIndexes[0]
+ mimeDataProvider.sourceCell = cellAtIndex(source_index)
+ mimeDataProvider.loadSelectedData()
+ } else {
+ const current_index = selectionModel.currentIndex
+ const current_cell = cellAtIndex(current_index)
+ mimeDataProvider.sourceCell = current_cell
+ mimeDataProvider.loadDataFromModel(current_cell, current_index, model)
+ }
+ mimeDataProvider.includeCutData = true
+ }
+
+ function pasteFromClipboard()
+ {
+ visibleCellsConnection.blockConnection(true)
+ const current_index = selectionModel.currentIndex
+ const current_cell = cellAtIndex(current_index)
+
+ let target_cells = new Set()
+ if (mimeDataProvider.size() === 1) {
+ if (selectionModel.hasSelection) {
+ for (let i in selectionModel.selectedIndexes) {
+ const selected_index = selectionModel.selectedIndexes[i]
+ mimeDataProvider.saveDataToModel(0, selected_index, model)
+ target_cells.add(tableView.cellAtIndex(selected_index))
+ }
+ } else {
+ const old_cell = mimeDataProvider.cellAt(0)
+ let new_cell = Qt.point(old_cell.x, old_cell.y)
+ new_cell.x += current_cell.x - mimeDataProvider.sourceCell.x
+ new_cell.y += current_cell.y - mimeDataProvider.sourceCell.y
+ mimeDataProvider.saveDataToModel(0, index(new_cell.y, new_cell.x), model)
+ target_cells.add(new_cell)
+ }
+ } else if (mimeDataProvider.size() > 1) {
+ for (let i = 0; i < mimeDataProvider.size(); ++i) {
+ let cell_i = mimeDataProvider.cellAt(i)
+ cell_i.x += current_cell.x - mimeDataProvider.sourceCell.x
+ cell_i.y += current_cell.y - mimeDataProvider.sourceCell.y
+ mimeDataProvider.saveDataToModel(i, index(cell_i.y, cell_i.x), model)
+ target_cells.add(cell_i)
+ }
+ }
+ if (mimeDataProvider.includeCutData) {
+ for (let i = 0; i < mimeDataProvider.size(); ++i) {
+ const cell_i = mimeDataProvider.cellAt(i)
+ if (!target_cells.has(cell_i))
+ model.clearItemData(index(cell_i.y, cell_i.x))
+ }
+ mimeDataProvider.includeCutData = false
+ }
+ visibleCellsConnection.blockConnection(false)
+ visibleCellsConnection.updateViewArea()
+ }
+
+ function resetColumnReordering()
+ {
+ clearColumnReordering()
+ model.resetColumnMapping()
+ }
+
+ function resetRowReordering()
+ {
+ clearRowReordering()
+ model.resetRowMapping()
+ }
+
+ ScrollBar.horizontal: ScrollBar { }
+ ScrollBar.vertical: ScrollBar { }
+
+ rowHeightProvider: function(row) {
+ const height = explicitRowHeight(row)
+ if (height === 0)
+ return 0
+ else if (height > 0)
+ return Math.max(height, 30)
+ return implicitRowWidth(row)
+ }
+
+ columnWidthProvider: function(column) {
+ const width = explicitColumnWidth(column)
+ if (width === 0)
+ return 0
+ else if (width > 0)
+ return Math.max(width, 30)
+ return implicitColumnWidth(column)
+ }
+
+ delegate: TableCell {
+ required property var model
+
+ implicitWidth: 90
+ implicitHeight: 36
+ text: model.display ?? ""
+ // We don't create data for empty cells to reduce
+ // the memory usage in case of huge model.
+ // If a cell does not have data and it's not highlighted neither
+ // the model.highlight is undefined which is replaced with false value.
+ highlight: model.highlight ?? false
+ edit: model.edit ?? ""
+
+ onCommit: text => model.edit = text
+ }
+
+ Keys.onPressed: function (event) {
+ if (event.matches(StandardKey.Copy)) {
+ copyToClipboard()
+ } else if (event.matches(StandardKey.Cut)) {
+ cutToClipboard()
+ } else if (event.matches(StandardKey.Paste)) {
+ pasteFromClipboard()
+ } else if (event.matches(StandardKey.Delete)) {
+ visibleCellsConnection.blockConnection()
+ if (selectionModel.hasSelection)
+ model.clearItemData(selectionModel.selectedIndexes)
+ else
+ model.clearItemData(selectionModel.currentIndex)
+ visibleCellsConnection.blockConnection(false)
+ visibleCellsConnection.updateViewArea()
+ }
+ }
+
+ Connections {
+ id: visibleCellsConnection
+ target: SpreadModel
+
+ function onDataChanged(tl, br, roles)
+ {
+ updateViewArea()
+ }
+
+ // The model is updated, then the visible area needs to be updated as well.
+ // Maybe some cells need to get the display data again
+ // due to their data, if it's a formula.
+ function updateViewArea()
+ {
+ for (let row = tableView.topRow; row <= tableView.bottomRow; ++row) {
+ for (let column = tableView.leftColumn; column <= tableView.rightColumn; ++column) {
+ SpreadModel.update(row, column)
+ }
+ }
+ }
+
+ // Blocks/unblocks the connection. This function is useful when
+ // some actions may update a large amount of data in the model,
+ // or may update a cell which affects other cells,
+ // for example clipboard actions and drag/drop actions.
+ // Block the connection, update the model, unblock the connection,
+ // and the call the updateViewArea() function to update the view.
+ function blockConnection(block=true)
+ {
+ visibleCellsConnection.enabled = !block
+ }
+ }
+
+ MouseArea {
+ id: dragArea
+
+ property point dragCell: Qt.point(-1, -1)
+ property bool hadSelection: false
+
+ anchors.fill: parent
+ drag.axis: Drag.XandYAxis
+ drag.target: dropArea
+ acceptedButtons: Qt.LeftButton
+ cursorShape: drag.active ? Qt.ClosedHandCursor : Qt.ArrowCursor
+
+ onPressed: function(mouse) {
+ mouse.accepted = false
+ // only when Alt modifier is pressed
+ if (mouse.modifiers !== Qt.AltModifier)
+ return
+ // check cell under press position
+ const position = Qt.point(mouse.x, mouse.y)
+ const cell = tableView.cellAtPosition(position, true)
+ if (cell.x < 0 || cell.y < 0)
+ return
+ // check selected indexes
+ const index = tableView.index(cell.y, cell.x)
+ hadSelection = selectionModel.hasSelection
+ if (!hadSelection)
+ selectionModel.select(index, ItemSelectionModel.Select)
+ if (!selectionModel.isSelected(index))
+ return
+ // store selected data
+ mimeDataProvider.reset()
+ mimeDataProvider.loadSelectedData()
+ // accept dragging
+ if (mimeDataProvider.size() > 0) {
+ mouse.accepted = true
+ dragCell = cell
+ }
+
+ dropArea.startDragging()
+ }
+
+ onReleased: {
+ dropArea.stopDragging()
+ // reset selection, if dragging caused the selection
+ if (!hadSelection)
+ selectionModel.clearSelection()
+ hadSelection = false
+ dragCell = Qt.point(-1, -1)
+ }
+ }
+ }
+
+ DropArea {
+ id: dropArea
+
+ property point dropCell: Qt.point(-1, -1)
+
+ anchors.fill: tableView
+ Drag.active: dragArea.drag.active
+
+ function startDragging()
+ {
+ // block updating visible area
+ visibleCellsConnection.blockConnection()
+ }
+
+ function stopDragging()
+ {
+ Drag.drop()
+ // unblock update visible area
+ visibleCellsConnection.blockConnection(false)
+ visibleCellsConnection.updateViewArea() // now update visible area
+ }
+
+ onDropped: {
+ const position = Qt.point(dragArea.mouseX, dragArea.mouseY)
+ dropCell = tableView.cellAtPosition(position, true)
+ if (dropCell.x < 0 || dropCell.y < 0)
+ return
+ if (dragArea.dragCell === dropCell)
+ return
+
+ tableView.model.clearItemData(selectionModel.selectedIndexes)
+ for (let i = 0; i < mimeDataProvider.size(); ++i) {
+ let cell = mimeDataProvider.cellAt(i)
+ cell.x += dropCell.x - dragArea.dragCell.x
+ cell.y += dropCell.y - dragArea.dragCell.y
+ const index = tableView.index(cell.y, cell.x)
+ mimeDataProvider.saveDataToModel(i, index, tableView.model)
+ }
+ mimeDataProvider.reset()
+ selectionModel.clearSelection()
+
+ const drop_index = tableView.index(dropCell.y, dropCell.x)
+ selectionModel.setCurrentIndex(drop_index, ItemSelectionModel.Current)
+
+ tableView.model.clearHighlight()
+ }
+
+ onPositionChanged: {
+ const position = Qt.point(dragArea.mouseX, dragArea.mouseY)
+ // cell is the cell that currently mouse is over it
+ const cell = tableView.cellAtPosition(position, true)
+ // dropCell is the cell that it was under the mouse's last position
+ // if the last and current cells are the same, then there is no need
+ // to update highlight, as nothing is changed since last time.
+ if (cell === dropCell)
+ return
+ // if something is changed, it means that if the current cell is changed,
+ // then clear highlighted cells and update the dropCell.
+ tableView.model.clearHighlight()
+ dropCell = cell
+ // if the current cell was invalid (mouse is out side of the TableView)
+ // then no need to update highlight
+ if (cell.x < 0 || cell.y < 0)
+ return
+ // if dragged cell is the same as the (possibly) dropCell
+ // then no need to highlight any cells
+ if (dragArea.dragCell === dropCell)
+ return
+ // if the dropCell is not the same as the dragging cell and also
+ // is not the same as the cell at the mouse's last position
+ // then highlights the target cells
+ for (let i in selectionModel.selectedIndexes) {
+ const old_index = selectionModel.selectedIndexes[i]
+ let cell = tableView.cellAtIndex(old_index)
+ cell.x += dropCell.x - dragArea.dragCell.x
+ cell.y += dropCell.y - dragArea.dragCell.y
+ const new_index = tableView.index(cell.y, cell.x)
+ tableView.model.setHighlight(new_index, true)
+ }
+ }
+ }
+ }
+ }
+
+ SelectionRectangle {
+ id: selectionRectangle
+ target: tableView
+ selectionMode: SelectionRectangle.Auto
+
+ topLeftHandle: Rectangle {
+ width: 20
+ height: 20
+ radius: 10
+ color: Qt.styleHints.colorScheme === Qt.Light ? palette.highlight.lighter(1.4)
+ : palette.highlight.darker(1.4)
+ visible: SelectionRectangle.control.active
+ }
+
+ bottomRightHandle: Rectangle {
+ width: 20
+ height: 20
+ radius: 10
+ color: Qt.styleHints.colorScheme === Qt.Light ? palette.highlight.lighter(1.4)
+ : palette.highlight.darker(1.4)
+ visible: SelectionRectangle.control.active
+ }
+ }
+
+ SpreadSelectionModel {
+ id: selectionModel
+ behavior: SpreadSelectionModel.SelectCells
+ }
+
+ SpreadMimeDataProvider {
+ id: mimeDataProvider
+
+ property bool includeCutData: false
+ property point sourceCell: Qt.point(-1, -1)
+
+ function loadSelectedData()
+ {
+ for (let i in selectionModel.selectedIndexes) {
+ const index = selectionModel.selectedIndexes[i]
+ const cell = tableView.cellAtIndex(index)
+ loadDataFromModel(cell, index, tableView.model)
+ }
+ }
+
+ function resetProvider()
+ {
+ sourceCell = Qt.point(-1, -1)
+ includeCutData = false
+ reset()
+ }
+ }
+
+ HelpDialog {
+ id: helpDialog
+ anchors.centerIn: parent
+ }
+}
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/TableCell.qml b/examples/quickcontrols/spreadsheets/Spreadsheets/TableCell.qml
new file mode 100644
index 0000000000..80941ad79a
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/TableCell.qml
@@ -0,0 +1,41 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+
+Rectangle {
+ id: root
+ clip: true
+
+ property alias text: textItem.text
+ property bool highlight: false
+ required property bool current
+ required property bool selected
+ required property bool editing
+ required property string edit
+
+ signal commit(text: string)
+
+ readonly property bool __darkMode: Qt.styleHints.colorScheme === Qt.Dark
+ border {
+ width: (!editing && current) ? 1 : 0
+ color: current ? palette.highlight.darker(__darkMode ? 0.7 : 1.9) : palette.base
+ }
+ readonly property color __highlight_color: __darkMode
+ ? palette.highlight.darker(1.9)
+ : palette.highlight.lighter(1.9)
+ color: highlight ? __highlight_color : selected ? palette.highlight : palette.base
+
+ Label {
+ id: textItem
+ anchors { fill: parent; margins: 5 }
+ visible: !root.editing
+ }
+
+ TableView.editDelegate: TextField {
+ anchors.fill: root
+ text: root.edit
+ TableView.onCommit: root.commit(text)
+ }
+}
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/datamodel.cpp b/examples/quickcontrols/spreadsheets/Spreadsheets/datamodel.cpp
new file mode 100644
index 0000000000..c27b693173
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/datamodel.cpp
@@ -0,0 +1,266 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "datamodel.h"
+#include "spreadrole.h"
+
+bool DataModel::empty() const
+{
+ return m_keys.empty();
+}
+
+std::pair<SpreadKey, SpreadKey> DataModel::clearHighlight()
+{
+ SpreadKey top_left{INT_MAX, INT_MAX};
+ SpreadKey bottom_right{-1, -1};
+
+ for (auto it = m_cells.begin(); it != m_cells.end();) {
+ it.value().set(spread::Role::Hightlight, false);
+ if (it.key().first < top_left.first)
+ top_left.first = it.key().first;
+ if (it.key().second < top_left.second)
+ top_left.second = it.key().second;
+ if (bottom_right.first < it.key().first)
+ bottom_right.first = it.key().first;
+ if (bottom_right.second < it.key().second)
+ bottom_right.second = it.key().second;
+ if (it.value().isNull()) {
+ m_keys.remove(it.value().id);
+ auto cit = spread::make_const(m_cells, it);
+ it = m_cells.erase(cit);
+ } else {
+ ++it;
+ }
+ }
+
+ return std::make_pair(top_left, bottom_right);
+}
+
+bool DataModel::setHighlight(const SpreadKey &key, bool highlight)
+{
+ if (auto it = m_cells.find(key); it != m_cells.end()) {
+ it.value().set(spread::Role::Hightlight, highlight);
+ if (it.value().isNull()) {
+ m_keys.remove(it.value().id);
+ auto cit = spread::make_const(m_cells, it);
+ m_cells.erase(cit);
+ }
+ return true;
+ }
+ if (highlight) {
+ SpreadCell cell;
+ cell.set(spread::Role::Hightlight, true);
+ cell.id = ++lastId;
+ m_cells.insert(key, cell);
+ m_keys.insert(cell.id, key);
+ return true;
+ }
+ // we skipped false highlight for non-existing cell
+ // because we don't store cells with only false hightlight data
+ // to save memory
+ return false;
+}
+
+QVariant DataModel::getData(int id, int role) const
+{
+ auto it_key = m_keys.find(id);
+ if (it_key == m_keys.end())
+ return QVariant{};
+ const SpreadKey &key = it_key.value();
+ auto it_cell = m_cells.find(key);
+ if (it_cell == m_cells.end())
+ return QVariant{};
+ return it_cell.value().get(role);
+}
+
+QVariant DataModel::getData(const SpreadKey &key, int role) const
+{
+ auto it = m_cells.find(key);
+ return it == m_cells.end() ? QVariant{} : it.value().get(role);
+}
+
+bool DataModel::setData(const SpreadKey &key, const QVariant &value, int role)
+{
+ // special roles
+ switch (role) {
+ case spread::Role::Hightlight:
+ return setHighlight(key, value.toBool());
+ default: break;
+ }
+
+ // no special handling for the role
+ if (auto it = m_cells.find(key); it != m_cells.end()) {
+ it.value().set(role, value);
+ if (it.value().isNull()) {
+ clearData(key);
+ return true;
+ }
+ } else {
+ SpreadCell cell;
+ cell.set(role, value);
+ cell.id = ++lastId;
+ if (!cell.isNull()) {
+ m_cells.insert(key, cell);
+ m_keys.insert(cell.id, key);
+ }
+ }
+
+ return true;
+}
+
+bool DataModel::clearData(const SpreadKey &key)
+{
+ auto find_key = [&key](const auto &i) { return i == key; };
+ auto it = std::find_if(m_keys.cbegin(), m_keys.cend(), find_key);
+ if (it == m_keys.cend())
+ return 0;
+ m_keys.erase(it);
+ return m_cells.remove(key) > 0;
+}
+
+void DataModel::shiftColumns(int from, int count)
+{
+ if (count > 0) {
+ // the reason for reverse iteration is because of the coverage of
+ // the updated keys (bigger keys) and existing keys (next keys)
+ QMapIterator i(m_cells);
+ i.toBack();
+ while (i.hasPrevious()) {
+ i.previous();
+ if (i.key().second >= from) {
+ SpreadKey key = i.key();
+ SpreadCell cell = i.value();
+ m_cells.remove(key);
+ key.second += count;
+ m_cells.insert(key, cell);
+ }
+ }
+ } else if (count < 0) {
+ // the reason for normal iteration is because of the coverage of
+ // the updated keys (smaller keys) and existing keys (previous keys)
+ for (auto it = m_cells.begin(); it != m_cells.end(); ++it) {
+ if (it.key().second >= from) {
+ SpreadKey key = it.key();
+ SpreadCell cell = it.value();
+ m_cells.remove(key);
+ key.second += count;
+ m_cells.insert(key, cell);
+ }
+ }
+ }
+
+ if (count != 0) {
+ for (auto it = m_keys.begin(); it != m_keys.end(); ++it) {
+ SpreadKey &key = it.value();
+ if (key.second >= from)
+ key.second += count;
+ }
+ }
+}
+
+void DataModel::removeColumnCells(int column)
+{
+ for (auto it = m_cells.begin(); it != m_cells.end(); ) {
+ if (it.key().second == column) {
+ auto cit = spread::make_const(m_cells, it);
+ it = m_cells.erase(cit);
+ } else {
+ ++it;
+ }
+ }
+
+ for (auto it = m_keys.begin(); it != m_keys.end(); ) {
+ if (it.value().second == column) {
+ auto cit = spread::make_const(m_keys, it);
+ it = m_keys.erase(cit);
+ } else {
+ ++it;
+ }
+ }
+}
+
+void DataModel::shiftRows(int from, int count)
+{
+ if (count > 0) {
+ // the reason for reverse iteration is because of the coverage of
+ // the updated keys (bigger keys) and existing keys (next keys)
+ QMapIterator i(m_cells);
+ i.toBack();
+ while (i.hasPrevious()) {
+ if (i.key().first < from)
+ break;
+ SpreadKey key = i.key();
+ SpreadCell cell = i.value();
+ m_cells.remove(key);
+ key.first += count;
+ m_cells.insert(key, cell);
+ }
+ } else if (count < 0) {
+ // the reason for normal iteration is because of the coverage of
+ // the updated keys (smaller keys) and existing keys (previous keys)
+ for (auto it = m_cells.begin(); it != m_cells.end(); ++it) {
+ if (it.key().first >= from) {
+ SpreadKey key = it.key();
+ SpreadCell cell = it.value();
+ m_cells.remove(key);
+ key.first += count;
+ m_cells.insert(key, cell);
+ }
+ }
+ }
+
+ if (count != 0) {
+ for (auto it = m_keys.begin(); it != m_keys.end(); ++it) {
+ SpreadKey &key = it.value();
+ if (key.first >= from)
+ key.first += count;
+ }
+ }
+}
+
+void DataModel::removeRowCells(int row)
+{
+ for (auto it = m_cells.begin(); it != m_cells.end(); ) {
+ if (it.key().first == row) {
+ auto cit = spread::make_const(m_cells, it);
+ it = m_cells.erase(cit);
+ } else {
+ ++it;
+ }
+ }
+
+ for (auto it = m_keys.begin(); it != m_keys.end(); ) {
+ if (it.value().first == row) {
+ auto cit = spread::make_const(m_keys, it);
+ it = m_keys.erase(cit);
+ } else {
+ ++it;
+ }
+ }
+}
+
+int DataModel::createId(const SpreadKey &key)
+{
+ auto find_key = [&key](const auto &elem) { return key == elem; };
+ auto it = std::find_if(m_keys.begin(), m_keys.end(), find_key);
+ if (it != m_keys.end())
+ return it.key();
+ const int id = ++lastId;
+ m_keys.insert(id, key);
+ return id;
+}
+
+int DataModel::getId(const SpreadKey &key) const
+{
+ auto find_key = [&key](const auto &elem) { return key == elem; };
+ auto it = std::find_if(m_keys.begin(), m_keys.end(), find_key);
+ if (it == m_keys.end())
+ return 0;
+ return it.key();
+}
+
+SpreadKey DataModel::getKey(int id) const
+{
+ auto it = m_keys.find(id);
+ return it == m_keys.end() ? SpreadKey{-1, -1} : it.value();
+}
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/datamodel.h b/examples/quickcontrols/spreadsheets/Spreadsheets/datamodel.h
new file mode 100644
index 0000000000..de64f4d0bd
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/datamodel.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef DATAMODEL_H
+#define DATAMODEL_H
+
+#include "spreadcell.h"
+#include "spreadkey.h"
+
+/**********************************************************
+ * The DataModel struct manages the binding of data, keys,
+ * and ids. There are some special functionalities that are
+ * only related to data and keys, like
+ * shifting columns and rows
+ * inserting column and row
+ * removing columns and rows, and
+ * managing only the data.
+ * This struct is extracted from the SpreadModel, and the
+ * intention is to simplify the SpreadModel class and also
+ * encapsulate any data-related concepts.
+ **********************************************************/
+struct DataModel
+{
+ bool empty() const;
+
+ /******************************************************
+ * Unsets highlight of highlighted data.
+ * Returns a pair of top-left and bottom-right keys of updated cells
+ ******************************************************/
+ std::pair<SpreadKey, SpreadKey> clearHighlight();
+ /******************************************************
+ * Sets highlight role of data.
+ * Returns true if any cell updated, otherwise, false.
+ ******************************************************/
+ bool setHighlight(const SpreadKey &key, bool highlight);
+
+ QVariant getData(int id, int role) const;
+ QVariant getData(const SpreadKey &key, int role) const;
+ bool setData(const SpreadKey &key, const QVariant &value, int role);
+ bool clearData(const SpreadKey &key);
+
+ void shiftColumns(int from, int count);
+ void removeColumnCells(int column);
+
+ void shiftRows(int from, int count);
+ void removeRowCells(int row);
+
+ /******************************************************
+ * If the key already exists in the model, returns the
+ * id; otherwise, adds the key, assignes an id, and
+ * returns the id.
+ ******************************************************/
+ int createId(const SpreadKey &key);
+ int getId(const SpreadKey &key) const;
+ SpreadKey getKey(int id) const;
+
+private:
+ uint lastId = 0;
+ QMap<SpreadKey, SpreadCell> m_cells;
+ QMap<int, SpreadKey> m_keys;
+};
+
+#endif // DATAMODEL_H
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/copy.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/copy.svg
new file mode 100644
index 0000000000..9510d9750f
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/copy.svg
@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="File / copy_general_fill">
+<path id="Layer01" fill-rule="evenodd" clip-rule="evenodd" d="M6 20C5.44754 20 5 19.5524 5 19.0003V6C5 5.44772 4.55228 5 4 5C3.44772 5 3 5.44772 3 6V19.0003C3 20.6573 4.34333 22 6 22H16C16.5523 22 17 21.5523 17 21C17 20.4477 16.5523 20 16 20H6Z" fill="#0D0D0D"/>
+<rect id="Layer02" x="6" y="2" width="14" height="17" rx="2" fill="#0D0D0D"/>
+</g>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/cut.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/cut.svg
new file mode 100644
index 0000000000..c87d677894
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/cut.svg
@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Edit / cut">
+<path id="Layer01" fill-rule="evenodd" clip-rule="evenodd" d="M19.4142 3H21.2929C21.6834 3 22 3.31658 22 3.70711C22 3.89464 21.9255 4.0745 21.7929 4.20711L15 11L13 9L18.7071 3.29289C18.8946 3.10536 19.149 3 19.4142 3ZM10 12L12 14L9.70711 16.2929C9.68701 16.313 9.66627 16.3321 9.64495 16.3501C9.87301 16.8531 10 17.4117 10 18C10 20.2091 8.20914 22 6 22C3.79086 22 2 20.2091 2 18C2 15.7909 3.79086 14 6 14C6.58827 14 7.14688 14.127 7.64991 14.3551C7.66794 14.3337 7.68701 14.313 7.70711 14.2929L10 12ZM8 18C8 19.1046 7.10457 20 6 20C4.89543 20 4 19.1046 4 18C4 16.8954 4.89543 16 6 16C7.10457 16 8 16.8954 8 18Z" fill="#0D0D0D"/>
+<path id="Layer02" fill-rule="evenodd" clip-rule="evenodd" d="M7.64991 9.64495C7.14688 9.87301 6.58827 10 6 10C3.79086 10 2 8.20914 2 6C2 3.79086 3.79086 2 6 2C8.20914 2 10 3.79086 10 6C10 6.58827 9.87301 7.14688 9.64495 7.64992C9.66627 7.66795 9.68701 7.68701 9.70711 7.70711L21.7929 19.7929C21.9255 19.9255 22 20.1054 22 20.2929C22 20.6834 21.6834 21 21.2929 21H19.4142C19.149 21 18.8946 20.8946 18.7071 20.7071L7.70711 9.70711C7.68701 9.68701 7.66794 9.66627 7.64991 9.64495ZM8 6C8 7.10457 7.10457 8 6 8C4.89543 8 4 7.10457 4 6C4 4.89543 4.89543 4 6 4C7.10457 4 8 4.89543 8 6ZM13 12C13 12.5523 12.5523 13 12 13C11.4477 13 11 12.5523 11 12C11 11.4477 11.4477 11 12 11C12.5523 11 13 11.4477 13 12Z" fill="#0D0D0D"/>
+</g>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/help.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/help.svg
new file mode 100644
index 0000000000..a911efaade
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/help.svg
@@ -0,0 +1,5 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="Navigation / help_question_circle_fill">
+<path id="Layer01" fill-rule="evenodd" clip-rule="evenodd" d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2ZM11.0859 13.1913C11.0305 13.6404 11.4243 14 11.8735 14C12.3172 14 12.65 13.6271 12.7863 13.2017C12.8088 13.1315 12.834 13.0635 12.8614 12.9937C12.9699 12.7167 13.2775 12.3375 13.7841 11.8562C14.1605 11.4771 14.4572 11.1161 14.6743 10.7734C14.8914 10.4307 15 10.0187 15 9.5375C15 8.72083 14.7033 8.09375 14.1098 7.65625C13.5164 7.21875 12.8143 7 12.0038 7C11.1787 7 10.5093 7.21875 9.99543 7.65625C9.47937 8.13493 9.18688 8.71516 9.03161 9.20479C8.88562 9.66512 9.26613 10.0625 9.74578 10.0625C10.2209 10.0625 10.5687 9.65217 10.7158 9.19697C10.7473 9.09933 10.7885 9.0118 10.8422 8.94687C11.0955 8.64062 11.4827 8.4875 12.0038 8.4875C12.467 8.4875 12.8143 8.6151 13.0459 8.87031C13.2775 9.12552 13.3933 9.40625 13.3933 9.7125C13.3933 10.0042 13.3065 10.2776 13.1328 10.5328C12.9591 10.788 12.742 11.025 12.4814 11.2437C11.8446 11.8125 11.4537 12.2427 11.309 12.5344C11.2968 12.5589 11.2847 12.5825 11.2728 12.6058L11.2726 12.6061C11.1938 12.7598 11.1218 12.9004 11.0859 13.1913ZM13 16C13 15.4477 12.5523 15 12 15C11.4477 15 11 15.4477 11 16C11 16.5523 11.4477 17 12 17C12.5523 17 13 16.5523 13 16Z" fill="#0D0D0D"/>
+</g>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/hide.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/hide.svg
new file mode 100644
index 0000000000..08acd995ce
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/hide.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M19.4968 15.7897C20.2836 14.7793 20.9142 13.7515 21.4279 12.9142L21.4279 12.9142C21.6371 12.5732 21.8269 12.2638 22 12C21.8651 11.743 21.7267 11.4676 21.5817 11.179C20.1143 8.25938 17.9737 4 12 4C10.6125 4 9.41059 4.24746 8.36812 4.66102L11.717 8.00986C11.8105 8.00332 11.9048 8 12 8C14.2091 8 16 9.79086 16 12C16 12.0952 15.9967 12.1895 15.9901 12.283L19.4968 15.7897ZM2 12C2.55147 10.6765 3.50324 8.46339 5.28578 6.69999L8.55382 9.96803C8.20193 10.5635 8 11.2582 8 12C8 14.2091 9.79086 16 12 16C12.7418 16 13.4365 15.7981 14.032 15.4462L16.9327 18.347C15.5944 19.3254 13.9735 20 12 20C6.80109 20 4.08117 15.4622 2.47108 12.776C2.3024 12.4945 2.1459 12.2334 2 12ZM10 12C10 11.8208 10.0236 11.6472 10.0677 11.482L12.518 13.9323C12.3528 13.9764 12.1792 14 12 14C10.8954 14 10 13.1046 10 12Z" fill="#0D0D0D"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M2.29289 2.29289C2.68342 1.90237 3.31658 1.90237 3.70711 2.29289L21.7071 20.2929C22.0976 20.6834 22.0976 21.3166 21.7071 21.7071C21.3166 22.0976 20.6834 22.0976 20.2929 21.7071L2.29289 3.70711C1.90237 3.31658 1.90237 2.68342 2.29289 2.29289Z" fill="#0D0D0D"/>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_column_left.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_column_left.svg
new file mode 100644
index 0000000000..a11ce748aa
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_column_left.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4 2C2.89543 2 2 2.89543 2 4V20C2 21.1046 2.89543 22 4 22H20C21.1046 22 22 21.1046 22 20V4C22 2.89543 21.1046 2 20 2H4ZM12 16C11.4477 16 11 15.5523 11 15V13H9C8.44772 13 8 12.5523 8 12C8 11.4477 8.44772 11 9 11H11V9C11 8.44772 11.4477 8 12 8C12.5523 8 13 8.44772 13 9V11H15C15.5523 11 16 11.4477 16 12C16 12.5523 15.5523 13 15 13H13V15C13 15.5523 12.5523 16 12 16Z" fill="#0D0D0D"/>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_column_right.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_column_right.svg
new file mode 100644
index 0000000000..a11ce748aa
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_column_right.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4 2C2.89543 2 2 2.89543 2 4V20C2 21.1046 2.89543 22 4 22H20C21.1046 22 22 21.1046 22 20V4C22 2.89543 21.1046 2 20 2H4ZM12 16C11.4477 16 11 15.5523 11 15V13H9C8.44772 13 8 12.5523 8 12C8 11.4477 8.44772 11 9 11H11V9C11 8.44772 11.4477 8 12 8C12.5523 8 13 8.44772 13 9V11H15C15.5523 11 16 11.4477 16 12C16 12.5523 15.5523 13 15 13H13V15C13 15.5523 12.5523 16 12 16Z" fill="#0D0D0D"/>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_row_above.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_row_above.svg
new file mode 100644
index 0000000000..a11ce748aa
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_row_above.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4 2C2.89543 2 2 2.89543 2 4V20C2 21.1046 2.89543 22 4 22H20C21.1046 22 22 21.1046 22 20V4C22 2.89543 21.1046 2 20 2H4ZM12 16C11.4477 16 11 15.5523 11 15V13H9C8.44772 13 8 12.5523 8 12C8 11.4477 8.44772 11 9 11H11V9C11 8.44772 11.4477 8 12 8C12.5523 8 13 8.44772 13 9V11H15C15.5523 11 16 11.4477 16 12C16 12.5523 15.5523 13 15 13H13V15C13 15.5523 12.5523 16 12 16Z" fill="#0D0D0D"/>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_row_below.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_row_below.svg
new file mode 100644
index 0000000000..a11ce748aa
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/insert_row_below.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4 2C2.89543 2 2 2.89543 2 4V20C2 21.1046 2.89543 22 4 22H20C21.1046 22 22 21.1046 22 20V4C22 2.89543 21.1046 2 20 2H4ZM12 16C11.4477 16 11 15.5523 11 15V13H9C8.44772 13 8 12.5523 8 12C8 11.4477 8.44772 11 9 11H11V9C11 8.44772 11.4477 8 12 8C12.5523 8 13 8.44772 13 9V11H15C15.5523 11 16 11.4477 16 12C16 12.5523 15.5523 13 15 13H13V15C13 15.5523 12.5523 16 12 16Z" fill="#0D0D0D"/>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/pan.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/pan.svg
new file mode 100644
index 0000000000..4b31e22134
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/pan.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M5.29285 8.29287C5.68337 7.90234 6.31653 7.90234 6.70706 8.29286C7.09759 8.68338 7.0976 9.31654 6.70707 9.70707L5.41417 11H9.00002C9.55231 11 10 11.4477 10 12C10 12.5523 9.55231 13 9.00002 13H5.41418L6.70706 14.2929C7.09759 14.6834 7.0976 15.3165 6.70707 15.7071C6.31655 16.0976 5.68339 16.0976 5.29286 15.7071L2.36357 12.7779C1.93399 12.3483 1.93398 11.6518 2.36356 11.2222L5.29285 8.29287ZM14 12C14 11.4477 14.4477 11 15 11H18.5857L17.2929 9.70714C16.9023 9.31661 16.9023 8.68345 17.2929 8.29292C17.6834 7.9024 18.3165 7.9024 18.7071 8.29292L21.6364 11.2222C22.0659 11.6518 22.0659 12.3483 21.6364 12.7778L18.7071 15.7071C18.3165 16.0977 17.6834 16.0977 17.2929 15.7071C16.9023 15.3166 16.9023 14.6834 17.2929 14.2929L18.5858 13H15C14.4477 13 14 12.5523 14 12Z" fill="#0D0D0D"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M8.29295 5.25147C7.90243 5.642 7.90243 6.27516 8.29295 6.66569C8.68348 7.05621 9.31664 7.05621 9.70717 6.66569L11 5.37285V9.00001C11 9.55229 11.4477 10 12 10C12.5523 10 13 9.55229 13 9.00001V5.37273L14.293 6.66569C14.6835 7.05621 15.3166 7.05621 15.7072 6.66569C16.0977 6.27516 16.0977 5.642 15.7072 5.25147L12.7779 2.32218C12.3483 1.89261 11.6518 1.8926 11.2222 2.32218L8.29295 5.25147ZM13.0003 18.5441L13 14.9999C12.9999 14.4476 12.5522 14 11.9999 14C11.4476 14.0001 10.9999 14.4478 11 15.0001L11.0003 18.5447L9.7071 17.2515C9.31657 16.8609 8.68341 16.861 8.29289 17.2515C7.90237 17.642 7.90237 18.2752 8.2929 18.6657L11.2223 21.595C11.6518 22.0246 12.3483 22.0245 12.7779 21.595L15.7071 18.6657C16.0976 18.2752 16.0976 17.642 15.7071 17.2515C15.3166 16.8609 14.6834 16.861 14.2929 17.2515L13.0003 18.5441Z" fill="#0D0D0D"/>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/paste.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/paste.svg
new file mode 100644
index 0000000000..ceb3e34169
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/paste.svg
@@ -0,0 +1,6 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="File / paste_general_fill">
+<path id="Layer01" d="M6 19.875C6 21.0486 6.96431 22 8.15385 22L17.8462 22C19.0357 22 20 21.0486 20 19.875L20 7.125C20 5.95139 19.0357 5 17.8462 5L8.15385 5C6.96431 5 6 5.95139 6 7.125L6 19.875Z" fill="#0D0D0D"/>
+<path id="Layer02" fill-rule="evenodd" clip-rule="evenodd" d="M5 18C3.89543 18 3 17.1046 3 16V4C3 2.89543 3.89543 2 5 2H14C15.1046 2 16 2.89543 16 4L7 4C5.89543 4 5 4.89543 5 6L5 18Z" fill="#0D0D0D"/>
+</g>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/remove_column.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/remove_column.svg
new file mode 100644
index 0000000000..2940d0a3c7
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/remove_column.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4 2C2.89543 2 2 2.89543 2 4V20C2 21.1046 2.89543 22 4 22H20C21.1046 22 22 21.1046 22 20V4C22 2.89543 21.1046 2 20 2H4ZM9 11C8.44772 11 8 11.4477 8 12C8 12.5523 8.44772 13 9 13H15C15.5523 13 16 12.5523 16 12C16 11.4477 15.5523 11 15 11H9Z" fill="#0D0D0D"/>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/remove_row.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/remove_row.svg
new file mode 100644
index 0000000000..2940d0a3c7
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/remove_row.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M4 2C2.89543 2 2 2.89543 2 4V20C2 21.1046 2.89543 22 4 22H20C21.1046 22 22 21.1046 22 20V4C22 2.89543 21.1046 2 20 2H4ZM9 11C8.44772 11 8 11.4477 8 12C8 12.5523 8.44772 13 9 13H15C15.5523 13 16 12.5523 16 12C16 11.4477 15.5523 11 15 11H9Z" fill="#0D0D0D"/>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/reset_reordering.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/reset_reordering.svg
new file mode 100644
index 0000000000..d2e215251d
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/reset_reordering.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.21258 8C7.81596 6.15774 9.35083 5 11.8996 5C15.8328 5 19 8.14572 19 12C19 15.8543 15.8328 19 11.8996 19C8.5127 19 5.68925 16.6644 4.97458 13.5539C4.85091 13.0156 4.31431 12.6795 3.77605 12.8032C3.23779 12.9268 2.9017 13.4634 3.02537 14.0017C3.9478 18.0165 7.57647 21 11.8996 21C16.9138 21 21 16.9823 21 12C21 7.01772 16.9138 3 11.8996 3C8.69412 3 6.69438 4.48317 5 6.35199V5C5 4.44772 4.55228 4 4 4C3.44772 4 3 4.44772 3 5V8.9C3 9.50751 3.49249 10 4.1 10H8C8.55228 10 9 9.55228 9 9C9 8.44772 8.55228 8 8 8H6.21258Z" fill="#0D0D0D"/>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/icons/show.svg b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/show.svg
new file mode 100644
index 0000000000..b8e3141966
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/icons/show.svg
@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M21.5817 11.179C20.1143 8.25938 17.9737 4 12 4C5.4359 4 3.02564 9.53846 2 12C2.1459 12.2334 2.3024 12.4945 2.47108 12.776C4.08117 15.4622 6.80109 20 12 20C17.0808 20 19.8241 15.5284 21.4279 12.9142C21.6371 12.5732 21.8269 12.2638 22 12C21.8651 11.743 21.7267 11.4676 21.5817 11.179ZM14 12C14 13.1046 13.1046 14 12 14C10.8954 14 10 13.1046 10 12C10 10.8954 10.8954 10 12 10C13.1046 10 14 10.8954 14 12ZM16 12C16 14.2091 14.2091 16 12 16C9.79086 16 8 14.2091 8 12C8 9.79086 9.79086 8 12 8C14.2091 8 16 9.79086 16 12Z" fill="#0D0D0D"/>
+</svg>
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/spreadcell.cpp b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadcell.cpp
new file mode 100644
index 0000000000..b15818a426
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadcell.cpp
@@ -0,0 +1,69 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "spreadcell.h"
+#include "spreadrole.h"
+#include "spreadmodel.h"
+
+bool SpreadCell::isNull() const
+{
+ return !has(spread::Role::Display) && !has(spread::Role::Hightlight);
+}
+
+bool SpreadCell::has(int role) const
+{
+ switch (role) {
+ case spread::Role::Display:
+ case spread::Role::Edit:
+ return !text.isNull() && !text.isEmpty();
+ case spread::Role::Hightlight:
+ return highlight; // false highlight equals to no highlight set
+ default:
+ return false;
+ }
+}
+
+void SpreadCell::set(int role, const QVariant &data)
+{
+ switch (role) {
+ case spread::Role::Edit:
+ text = data.toString();
+ break;
+ case spread::Role::Hightlight:
+ highlight = data.toBool();
+ break;
+ default:
+ break;
+ }
+}
+
+QVariant SpreadCell::get(int role) const
+{
+ switch (role) {
+ case spread::Role::Edit:
+ return text;
+ case spread::Role::Display: {
+ const QString display_text = displayText();
+ return display_text.isNull() ? QVariant{} : display_text;
+ }
+ case spread::Role::Hightlight:
+ return highlight;
+ default:
+ return QVariant{};
+ }
+}
+
+QString SpreadCell::displayText() const
+{
+ SpreadModel *model = SpreadModel::instance();
+ const Formula formula = model->parseFormulaString(text);
+ if (!formula.isValid())
+ return text;
+ if (formula.firstOperandId() <= 0) // at least one arg should be available
+ return "#ERROR!";
+ if ((formula.firstOperandId() == id) || (formula.secondOperandId() == id))
+ return "#ERROR!"; // found loop
+ if (formula.includesLoop(model, model->dataModel()))
+ return "#ERROR!";
+ return model->formulaValueText(formula);
+}
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/spreadcell.h b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadcell.h
new file mode 100644
index 0000000000..0fb980ab9b
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadcell.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SPREADCELL_H
+#define SPREADCELL_H
+
+#include <QVariant>
+
+struct SpreadCell {
+ friend struct DataModel;
+
+ bool isNull() const;
+ bool has(int role) const;
+ void set(int role, const QVariant &data);
+ QVariant get(int role) const;
+
+private:
+ QString displayText() const;
+
+private:
+ uint id = 0;
+ QString text;
+ bool highlight = false;
+};
+
+#endif // SPREADCELL_H
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/spreadformula.cpp b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadformula.cpp
new file mode 100644
index 0000000000..87a961f40c
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadformula.cpp
@@ -0,0 +1,74 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "spreadformula.h"
+#include "datamodel.h"
+#include "spreadkey.h"
+#include "spreadrole.h"
+#include "spreadmodel.h"
+
+bool Formula::includesLoop(SpreadModel *model, const DataModel *dataModel, QSet<int> *history) const
+{
+ if (m_operator == Operator::Invalid)
+ return false;
+
+ if (history == nullptr) {
+ QSet<int> history;
+ return includesLoop(model, dataModel, &history);
+ }
+
+ if (m_operator == Operator::Sum) {
+ SpreadKey top_left = dataModel->getKey(m_cellIds.first);
+ SpreadKey bottom_right = dataModel->getKey(m_cellIds.second);
+ if (bottom_right.first < top_left.first)
+ std::swap(top_left.first, bottom_right.first);
+ if (bottom_right.second < top_left.second)
+ std::swap(top_left.second, bottom_right.second);
+ for (int row = top_left.first; row <= bottom_right.first; ++row) {
+ for (int column = top_left.second; column <= bottom_right.second; ++column) {
+ const int id = dataModel->getId(SpreadKey{row, column});
+ if (history->find(id) != history->end())
+ return true;
+ const QString edit_text = dataModel->getData(id, spread::Role::Edit).toString();
+ const Formula formula = model->parseFormulaString(edit_text);
+ if (!formula.isValid())
+ continue;
+ auto it = history->insert(id);
+ if (formula.includesLoop(model, dataModel, history))
+ return true;
+ auto cit = spread::make_const(*history, it);
+ history->erase(cit);
+ }
+ }
+ } else {
+ const int id_1 = m_cellIds.first;
+ if (history->find(id_1) != history->end())
+ return true;
+ const QString edit_text = dataModel->getData(id_1, spread::Role::Edit).toString();
+ const Formula formula = model->parseFormulaString(edit_text);
+ if (!formula.isValid())
+ return false;
+ auto it = history->insert(id_1);
+ if (formula.includesLoop(model, dataModel, history))
+ return true;
+ auto cit = spread::make_const(*history, it);
+ history->erase(cit);
+
+ if (m_operator != Operator::Assign) {
+ const int id_2 = m_cellIds.second;
+ if (history->find(id_2) != history->end())
+ return true;
+ const QString edit_text = dataModel->getData(id_2, spread::Role::Edit).toString();
+ const Formula formula = model->parseFormulaString(edit_text);
+ if (!formula.isValid())
+ return false;
+ auto it = history->insert(id_2);
+ if (formula.includesLoop(model, dataModel, history))
+ return true;
+ auto cit = spread::make_const(*history, it);
+ history->erase(cit);
+ }
+ }
+
+ return false;
+}
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/spreadformula.h b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadformula.h
new file mode 100644
index 0000000000..6548da10b3
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadformula.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SPREADFORMULA_H
+#define SPREADFORMULA_H
+
+#include <QSet>
+
+class DataModel;
+class SpreadModel;
+
+struct Formula {
+ enum class Operator {
+ Invalid = 0,
+ Assign,
+ Add,
+ Sub,
+ Div,
+ Mul,
+ Sum,
+ };
+
+ static Formula create(Operator op, int arg1, int arg2) {
+ Formula formula;
+ formula.m_operator = op;
+ formula.m_cellIds.first = arg1;
+ formula.m_cellIds.second = arg2;
+ return formula;
+ }
+
+ bool isValid() const { return m_operator != Operator::Invalid; }
+ int firstOperandId() const { return m_cellIds.first; }
+ int secondOperandId() const { return m_cellIds.second; }
+ Operator getOperator() const { return m_operator; }
+
+ bool includesLoop(SpreadModel *model, const DataModel *dataModel, QSet<int> *history = nullptr) const;
+
+private:
+ Operator m_operator = Operator::Invalid;
+ std::pair<int, int> m_cellIds = {0, 0};
+};
+
+#endif // SPREADFORMULA_H
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/spreadkey.h b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadkey.h
new file mode 100644
index 0000000000..741cedb0ee
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadkey.h
@@ -0,0 +1,23 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SPREADKEY_H
+#define SPREADKEY_H
+
+#include <utility>
+
+namespace spread {
+// make a const_iterator from an iterator for the same container
+// to avoid mixing iterators with const_iterators warning
+template <typename Container>
+constexpr typename Container::const_iterator make_const(Container c, typename Container::iterator i)
+{
+ return typename Container::const_iterator(i);
+}
+}
+
+// using std::pair<> as SpreadKey for now
+// for any further updates it could be anything
+using SpreadKey = std::pair<int, int>;
+
+#endif // SPREADKEY_H
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/spreadmimedataprovider.cpp b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadmimedataprovider.cpp
new file mode 100644
index 0000000000..25a8d1b118
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadmimedataprovider.cpp
@@ -0,0 +1,88 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "spreadmimedataprovider.h"
+
+#include <QMimeData>
+#include <QGuiApplication>
+#include <QClipboard>
+
+namespace {
+static inline constexpr auto MIMETYPE_SPREADMODEL = "application/x-qtexamplespreadmodel";
+static inline constexpr auto MIMETYPE_SELECTEDDATA = "model/data";
+static inline constexpr auto MIMETYPE_TEXT = "text/plain";
+}
+
+QMimeData *SpreadMimeDataProvider::saveToMimeData() const
+{
+ if (m_data.empty())
+ return nullptr;
+
+ QByteArray data;
+ QDataStream stream{&data, QDataStream::WriteOnly};
+ for (auto it = m_data.begin(); it != m_data.end(); ++it) {
+ const QPoint &cell = it->first;
+ const QMap<int, QVariant> &item_data = it->second;
+ stream << cell.x() << cell.y() << item_data;
+ }
+
+ QMimeData *mime_data = new QMimeData{};
+ mime_data->setData(MIMETYPE_SPREADMODEL, QByteArray{});
+ mime_data->setData(MIMETYPE_SELECTEDDATA, data);
+ return mime_data;
+}
+
+bool SpreadMimeDataProvider::loadFromMimeData(const QMimeData *mimeData)
+{
+ if (!mimeData)
+ return false;
+
+ if (!mimeData->hasFormat(MIMETYPE_SPREADMODEL))
+ return false;
+
+ QByteArray data = mimeData->data(MIMETYPE_SELECTEDDATA);
+ QDataStream stream{&data, QDataStream::ReadOnly};
+ while (!stream.atEnd()) {
+ QPoint cell;
+ QMap<int, QVariant> item_data;
+ stream >> cell.rx() >> cell.ry() >> item_data;
+ m_data.push_back(std::make_pair(cell, item_data));
+ }
+
+ return true;
+}
+
+bool SpreadMimeDataProvider::saveToClipboard()
+{
+ QMimeData *mime_data = saveToMimeData();
+ if (!mime_data)
+ return false;
+
+ QGuiApplication::clipboard()->setMimeData(mime_data);
+ return true;
+}
+
+bool SpreadMimeDataProvider::loadFromClipboard()
+{
+ const QMimeData *mime_data = QGuiApplication::clipboard()->mimeData();
+ if (!mime_data)
+ return false;
+
+ return loadFromMimeData(mime_data);
+}
+
+bool SpreadMimeDataProvider::saveDataToModel(int index,
+ const QModelIndex &modelIndex,
+ QAbstractItemModel *model) const
+{
+ const QMap<int, QVariant> &item_data = m_data.at(index).second;
+ return model->setItemData(modelIndex, item_data);
+}
+
+void SpreadMimeDataProvider::loadDataFromModel(const QPoint &cell,
+ const QModelIndex &index,
+ const QAbstractItemModel *model)
+{
+ const QMap<int, QVariant> &item_data = model->itemData(index);
+ m_data.push_back(std::make_pair(cell, item_data));
+}
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/spreadmimedataprovider.h b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadmimedataprovider.h
new file mode 100644
index 0000000000..5082890c89
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadmimedataprovider.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SPREADMIMEDATAPROVIDER_H
+#define SPREADMIMEDATAPROVIDER_H
+
+#include <QObject>
+#include <QAbstractItemModel>
+#include <QPoint>
+#include <QQmlEngine>
+
+class QMimeData;
+
+class SpreadMimeDataProvider : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+
+public:
+ QMimeData *saveToMimeData() const;
+ bool loadFromMimeData(const QMimeData *mimeData);
+
+ Q_INVOKABLE bool saveToClipboard();
+ Q_INVOKABLE bool loadFromClipboard();
+ Q_INVOKABLE void reset() { m_data.clear(); }
+ Q_INVOKABLE int size() const { return m_data.size(); }
+ Q_INVOKABLE QPoint cellAt(int index) const { return m_data.at(index).first; }
+ Q_INVOKABLE bool saveDataToModel(int index,
+ const QModelIndex &modelIndex,
+ QAbstractItemModel *model) const;
+ Q_INVOKABLE void loadDataFromModel(const QPoint &cell,
+ const QModelIndex &index,
+ const QAbstractItemModel *model);
+
+private:
+ std::vector<std::pair<QPoint, QMap<int, QVariant>>> m_data;
+};
+
+#endif // SPREADMIMEDATAPROVIDER_H
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/spreadmodel.cpp b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadmodel.cpp
new file mode 100644
index 0000000000..53f8feec33
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadmodel.cpp
@@ -0,0 +1,730 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "spreadmodel.h"
+#include "spreadrole.h"
+
+#include <QPoint>
+#include <QRegularExpression>
+
+int SpreadModel::columnNumberFromName(const QString &text)
+{
+ if (text.size() == 1)
+ return getModelColumn(text[0].toLatin1() - 'A');
+ else if (text.size() == 2)
+ return getModelColumn((text[0].toLatin1() - 'A' + 1) * 26 + (text[1].toLatin1() - 'A'));
+ return 0;
+}
+
+int SpreadModel::rowNumberFromName(const QString &text)
+{
+ return getModelRow(text.toInt() - 1);
+}
+
+SpreadModel *SpreadModel::instance()
+{
+ return s_instance;
+}
+
+SpreadModel *SpreadModel::create(QQmlEngine *, QJSEngine *)
+{
+ if (!s_instance)
+ s_instance = new SpreadModel {nullptr};
+ return s_instance;
+}
+
+void SpreadModel::update(int row, int column)
+{
+ if (!m_updateMutex.tryLock())
+ return;
+ column = getModelColumn(column);
+ row = getModelRow(row);
+ const QModelIndex index = this->index(row, column);
+ emit dataChanged(index, index, {spread::Role::Display,});
+ m_updateMutex.unlock();
+}
+
+void SpreadModel::clearHighlight()
+{
+ if (m_dataModel.empty())
+ return;
+
+ const auto [top_left, bottom_right] = m_dataModel.clearHighlight();
+
+ emit dataChanged(index(top_left.first, top_left.second),
+ index(bottom_right.first, bottom_right.second),
+ {spread::Role::Hightlight,});
+}
+
+void SpreadModel::setHighlight(const QModelIndex &index, bool highlight)
+{
+ if (!index.isValid())
+ return;
+ if (m_dataModel.setHighlight(SpreadKey{index.row(), index.column()}, highlight))
+ emit dataChanged(index, index, {spread::Role::Hightlight,});
+}
+
+int SpreadModel::rowCount(const QModelIndex &parent) const
+{
+ return m_size.first;
+}
+
+int SpreadModel::columnCount(const QModelIndex &parent) const
+{
+ return m_size.second;
+}
+
+QVariant SpreadModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant{};
+
+ const int row = index.row();
+ const int column = index.column();
+
+ return m_dataModel.getData(SpreadKey{row, column}, role);
+}
+
+bool SpreadModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!index.isValid())
+ return false;
+
+ const int row = index.row();
+ const int column = index.column();
+
+ if (m_dataModel.setData(SpreadKey{row, column}, value, role))
+ emit dataChanged(index, index);
+
+ return true;
+}
+
+bool SpreadModel::clearItemData(const QModelIndex &index)
+{
+ if (!index.isValid())
+ return false;
+ if (m_dataModel.clearData(SpreadKey{index.row(), index.column()})) {
+ emit dataChanged(index, index);
+ return true;
+ }
+ return false;
+}
+
+Qt::ItemFlags SpreadModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
+}
+
+QHash<int, QByteArray> SpreadModel::roleNames() const
+{
+ return {{spread::Role::Display, "display"},
+ {spread::Role::Edit, "edit"},
+ {spread::Role::ColumnName, "columnName"},
+ {spread::Role::RowName, "rowName"},
+ {spread::Role::Hightlight, "highlight"}};
+
+}
+
+QVariant SpreadModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ switch (role) {
+ case spread::Role::ColumnName:
+ case spread::Role::RowName:
+ break;
+ default:
+ return QVariant{};
+ }
+
+ switch (orientation) {
+ case Qt::Horizontal: {
+ constexpr char A = 'A';
+ const int view_section = getViewColumn(section);
+ if (view_section < 26) {
+ return QString{static_cast<char>(view_section + A)};
+ } else {
+ const int first = view_section / 26 - 1;
+ const int second = view_section % 26;
+ QString title{static_cast<char>(first + A)};
+ title += static_cast<char>(second + A);
+ return title;
+ }
+ }
+ case Qt::Vertical: {
+ return getViewRow(section) + 1;
+ }
+ }
+
+ return QVariant{};
+}
+
+bool SpreadModel::insertColumns(int column, int count, const QModelIndex &parent)
+{
+ if (count != 1) // TODO: implement inserting more than 1 columns
+ return false;
+
+ beginInsertColumns(QModelIndex{}, column, column + count - 1);
+ m_size.second += count;
+
+ // update model
+ m_dataModel.shiftColumns(column, count);
+
+ QMap<int, int> old_columns;
+ std::swap(old_columns, m_viewColumns);
+ for (auto it = old_columns.begin(); it != old_columns.end(); ++it) {
+ const int new_view_column = (it.value() < column) ? it.value() : it.value() + count;
+ const int new_model_column = (it.key() < column) ? it.key() : it.key() + count;
+ m_viewColumns.insert(new_model_column, new_view_column);
+ }
+
+ endInsertColumns();
+ return true;
+}
+
+bool SpreadModel::insertRows(int row, int count, const QModelIndex &parent)
+{
+ if (count != 1) // TODO: implement inserting more than 1 rows
+ return false;
+
+ beginInsertRows(QModelIndex{}, row, row + count - 1);
+ m_size.first += count;
+
+ // update model
+ m_dataModel.shiftRows(row, count);
+
+ endInsertRows();
+ return true;
+}
+
+bool SpreadModel::removeColumns(int column, int count, const QModelIndex &parent)
+{
+ if (count != 1) // TODO: implement removing more than 1 columns
+ return false;
+
+ beginRemoveColumns(QModelIndex{}, column, column + count - 1);
+ m_size.second -= count;
+
+ // update model
+ m_dataModel.removeColumnCells(column);
+ m_dataModel.shiftColumns(column + 1, -count);
+
+ endRemoveColumns();
+ return true;
+}
+
+bool SpreadModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (count != 1) // TODO: implement removing more than 1 rows
+ return false;
+
+ beginRemoveRows(QModelIndex{}, row, row + count - 1);
+ m_size.first -= count;
+
+ // update model
+ m_dataModel.removeRowCells(row);
+ m_dataModel.shiftRows(row + 1, -count);
+
+ endRemoveRows();
+ return true;
+}
+
+bool SpreadModel::clearItemData(const QModelIndexList &indexes)
+{
+ bool ok = true;
+ for (const QModelIndex &index : indexes)
+ ok &= clearItemData(index);
+ return ok;
+}
+
+bool SpreadModel::removeColumns(QModelIndexList indexes)
+{
+ auto greater = [](const QModelIndex &lhs, const QModelIndex &rhs)
+ {
+ return lhs.column() > rhs.column();
+ };
+ std::sort(indexes.begin(), indexes.end(), greater);
+ for (const QModelIndex &index : indexes)
+ removeColumn(index.column());
+ return true;
+}
+
+bool SpreadModel::removeRows(QModelIndexList indexes)
+{
+ auto greater = [](const QModelIndex &lhs, const QModelIndex &rhs)
+ {
+ return lhs.row() > rhs.row();
+ };
+ std::sort(indexes.begin(), indexes.end(), greater);
+ for (const QModelIndex &index : indexes)
+ removeRow(index.row());
+ return true;
+}
+
+void SpreadModel::mapColumn(int model, int view)
+{
+ if (model == view)
+ m_viewColumns.remove(model);
+ else
+ m_viewColumns[model] = view;
+ emit headerDataChanged(Qt::Horizontal, model, view);
+}
+
+void SpreadModel::mapRow(int model, int view)
+{
+ if (model == view)
+ m_viewRows.remove(model);
+ else
+ m_viewRows[model] = view;
+ emit headerDataChanged(Qt::Vertical, model, view);
+}
+
+Formula SpreadModel::parseFormulaString(const QString &qText)
+{
+ if (qText.isEmpty())
+ return Formula{};
+
+ QRegularExpression pattern_re;
+
+ // is formula
+ pattern_re.setPattern("^\\s*=.*");
+ QRegularExpressionMatch match = pattern_re.match(qText);
+ if (!match.hasMatch())
+ return Formula{};
+
+ // is Assignment: e.g. =A1
+ pattern_re.setPattern("^\\s*=\\s*([a-zA-Z]+)([1-9][0-9]*)\\s*$");
+ match = pattern_re.match(qText);
+ if (match.hasMatch()) {
+ const QString column_label = match.captured(1);
+ const QString row_label = match.captured(2);
+ const int column = columnNumberFromName(column_label);
+ const int row = rowNumberFromName(row_label);
+ const int cell_id = m_dataModel.createId(SpreadKey{row, column});
+ return Formula::create(Formula::Operator::Assign, cell_id, 0);
+ }
+
+ // is Addition: e.g. =A1+A2
+ pattern_re.setPattern("^\\s*=\\s*([a-zA-Z]+)([1-9][0-9]*)\\s*\\+\\s*([a-zA-Z]+)([1-9][0-9]*)\\s*$");
+ match = pattern_re.match(qText);
+ if (match.hasMatch()) {
+ // first argument
+ QString column_label = match.captured(1);
+ QString row_label = match.captured(2);
+ int column = columnNumberFromName(column_label);
+ int row = rowNumberFromName(row_label);
+ const int cell_id_1 = m_dataModel.createId(SpreadKey{row, column});
+ // second argument
+ column_label = match.captured(3);
+ row_label = match.captured(4);
+ column = columnNumberFromName(column_label);
+ row = rowNumberFromName(row_label);
+ const int cell_id_2 = m_dataModel.createId(SpreadKey{row, column});
+ // create formula
+ return Formula::create(Formula::Operator::Add, cell_id_1, cell_id_2);
+ }
+
+ // is Subtraction: e.g. =A1-A2
+ pattern_re.setPattern("^\\s*=\\s*([a-zA-Z]+)([1-9][0-9]*)\\s*\\-\\s*([a-zA-Z]+)([1-9][0-9]*)\\s*$");
+ match = pattern_re.match(qText);
+ if (match.hasMatch()) {
+ // first argument
+ QString column_label = match.captured(1);
+ QString row_label = match.captured(2);
+ int column = columnNumberFromName(column_label);
+ int row = rowNumberFromName(row_label);
+ const int cell_id_1 = m_dataModel.createId(SpreadKey{row, column});
+ // second argument
+ column_label = match.captured(3);
+ row_label = match.captured(4);
+ column = columnNumberFromName(column_label);
+ row = rowNumberFromName(row_label);
+ const int cell_id_2 = m_dataModel.createId(SpreadKey{row, column});
+ // create formula
+ return Formula::create(Formula::Operator::Sub, cell_id_1, cell_id_2);
+ }
+
+ // is Multiply: e.g. =A1*A2
+ pattern_re.setPattern("^\\s*=\\s*([a-zA-Z]+)([1-9][0-9]*)\\s*\\*\\s*([a-zA-Z]+)([1-9][0-9]*)\\s*$");
+ match = pattern_re.match(qText);
+ if (match.hasMatch()) {
+ // first argument
+ QString column_label = match.captured(1);
+ QString row_label = match.captured(2);
+ int column = columnNumberFromName(column_label);
+ int row = rowNumberFromName(row_label);
+ const int cell_id_1 = m_dataModel.createId(SpreadKey{row, column});
+ // second argument
+ column_label = match.captured(3);
+ row_label = match.captured(4);
+ column = columnNumberFromName(column_label);
+ row = rowNumberFromName(row_label);
+ const int cell_id_2 = m_dataModel.createId(SpreadKey{row, column});
+ // create formula
+ return Formula::create(Formula::Operator::Mul, cell_id_1, cell_id_2);
+ }
+
+ // is Division: e.g. =A1/A2
+ pattern_re.setPattern("^\\s*=\\s*([a-zA-Z]+)([1-9][0-9]*)\\s*\\/\\s*([a-zA-Z]+)([1-9][0-9]*)\\s*$");
+ match = pattern_re.match(qText);
+ if (match.hasMatch()) {
+ // first argument
+ QString column_label = match.captured(1);
+ QString row_label = match.captured(2);
+ int column = columnNumberFromName(column_label);
+ int row = rowNumberFromName(row_label);
+ const int cell_id_1 = m_dataModel.createId(SpreadKey{row, column});
+ // second argument
+ column_label = match.captured(3);
+ row_label = match.captured(4);
+ column = columnNumberFromName(column_label);
+ row = rowNumberFromName(row_label);
+ const int cell_id_2 = m_dataModel.createId(SpreadKey{row, column});
+ // create formula
+ return Formula::create(Formula::Operator::Div, cell_id_1, cell_id_2);
+ }
+
+ // is Summation: e.g. =SUM A1:A2
+ pattern_re.setPattern("^\\s*=\\s*[Ss][Uu][Mm]\\s+([a-zA-Z]+)([1-9][0-9]*)\\s*\\:\\s*([a-zA-Z]+)([1-9][0-9]*)\\s*$");
+ match = pattern_re.match(qText);
+ if (match.hasMatch()) {
+ // first argument
+ QString column_label = match.captured(1);
+ QString row_label = match.captured(2);
+ int column = columnNumberFromName(column_label);
+ int row = rowNumberFromName(row_label);
+ const int cell_id_1 = m_dataModel.createId(SpreadKey{row, column});
+ // second argument
+ column_label = match.captured(3);
+ row_label = match.captured(4);
+ column = columnNumberFromName(column_label);
+ row = rowNumberFromName(row_label);
+ const int cell_id_2 = m_dataModel.createId(SpreadKey{row, column});
+ // create formula
+ return Formula::create(Formula::Operator::Sum, cell_id_1, cell_id_2);
+ }
+
+ return Formula{};
+}
+
+QString SpreadModel::formulaValueText(const Formula &formula)
+{
+ switch (formula.getOperator()) {
+ case Formula::Operator::Assign: {
+ const QVariant value = m_dataModel.getData(formula.firstOperandId(), spread::Role::Display);
+ return value.isNull() ? QString{} : value.toString();
+ }
+ case Formula::Operator::Add: {
+ const QVariant value_1 = m_dataModel.getData(formula.firstOperandId(), spread::Role::Display);
+ const QVariant value_2 = m_dataModel.getData(formula.secondOperandId(), spread::Role::Display);
+ if (value_1.isNull() && value_2.isNull())
+ return "0";
+ // check int values
+ bool is_int_1 = true;
+ bool is_int_2 = true;
+ const int int_1 = value_1.isNull() ? 0 : value_1.toInt(&is_int_1);
+ const int int_2 = value_2.isNull() ? 0 : value_2.toInt(&is_int_2);
+ if (is_int_1 && is_int_2)
+ return QString::number(int_1 + int_2);
+ // check double values
+ bool is_double_1 = true;
+ bool is_double_2 = true;
+ const double double_1 = value_1.isNull() ? 0 : value_1.toDouble(&is_double_1);
+ const double double_2 = value_2.isNull() ? 0 : value_2.toDouble(&is_double_2);
+ if (is_double_1 && is_double_2)
+ return QString::number(double_1 + double_2);
+ return "#ERROR!";
+ }
+ case Formula::Operator::Sub: {
+ const QVariant value_1 = m_dataModel.getData(formula.firstOperandId(), spread::Role::Display);
+ const QVariant value_2 = m_dataModel.getData(formula.secondOperandId(), spread::Role::Display);
+ if (value_1.isNull() && value_2.isNull())
+ return "0";
+ // check int values
+ bool is_int_1 = true;
+ bool is_int_2 = true;
+ const int int_1 = value_1.isNull() ? 0 : value_1.toInt(&is_int_1);
+ const int int_2 = value_2.isNull() ? 0 : value_2.toInt(&is_int_2);
+ if (is_int_1 && is_int_2)
+ return QString::number(int_1 - int_2);
+ // check double values
+ bool is_double_1 = true;
+ bool is_double_2 = true;
+ const double double_1 = value_1.isNull() ? 0 : value_1.toDouble(&is_double_1);
+ const double double_2 = value_2.isNull() ? 0 : value_2.toDouble(&is_double_2);
+ if (is_double_1 && is_double_2)
+ return QString::number(double_1 - double_2);
+ return "#ERROR!";
+ }
+ case Formula::Operator::Mul: {
+ const QVariant value_1 = m_dataModel.getData(formula.firstOperandId(), spread::Role::Display);
+ const QVariant value_2 = m_dataModel.getData(formula.secondOperandId(), spread::Role::Display);
+ if (value_1.isNull() || value_2.isNull())
+ return "0";
+ // check int values
+ bool is_int_1 = true;
+ bool is_int_2 = true;
+ const int int_1 = value_1.toInt(&is_int_1);
+ const int int_2 = value_2.toInt(&is_int_2);
+ if (is_int_1 && is_int_2)
+ return QString::number(int_1 * int_2);
+ // check double values
+ bool is_double_1 = true;
+ bool is_double_2 = true;
+ const double double_1 = value_1.toDouble(&is_double_1);
+ const double double_2 = value_2.toDouble(&is_double_2);
+ if (is_double_1 && is_double_2)
+ return QString::number(double_1 * double_2);
+ return "#ERROR!";
+ }
+ case Formula::Operator::Div: {
+ const QVariant value_1 = m_dataModel.getData(formula.firstOperandId(), spread::Role::Display);
+ const QVariant value_2 = m_dataModel.getData(formula.secondOperandId(), spread::Role::Display);
+ if (value_1.isNull() && value_2.isNull())
+ return "#ERROR!";
+ // check int values
+ bool is_int_1 = true;
+ bool is_int_2 = true;
+ const int int_1 = value_1.isNull() ? 0 : value_1.toInt(&is_int_1);
+ const int int_2 = value_2.isNull() ? 0 : value_2.toInt(&is_int_2);
+ if (is_int_1 && is_int_2) {
+ if (int_2 == 0)
+ return "#ERROR!";
+ return QString::number(int_1 / int_2);
+ }
+ // check double values
+ bool is_double_1 = true;
+ bool is_double_2 = true;
+ const double double_1 = value_1.isNull() ? 0 : value_1.toDouble(&is_double_1);
+ const double double_2 = value_2.isNull() ? 0 : value_2.toDouble(&is_double_2);
+ if (is_double_1 && is_double_2) {
+ if (double_2 == 0)
+ return "#ERROR!";
+ return QString::number(double_1 / double_2);
+ }
+ return "#ERROR!";
+ }
+ case Formula::Operator::Sum: {
+ SpreadKey top_left = m_dataModel.getKey(formula.firstOperandId());
+ SpreadKey bottom_right = m_dataModel.getKey(formula.secondOperandId());
+ top_left.first = getViewRow(top_left.first);
+ top_left.second = getViewColumn(top_left.second);
+ bottom_right.first = getViewRow(bottom_right.first);
+ bottom_right.second = getViewColumn(bottom_right.second);
+ if (bottom_right.first < top_left.first)
+ std::swap(top_left.first, bottom_right.first);
+ if (bottom_right.second < top_left.second)
+ std::swap(top_left.second, bottom_right.second);
+ double sum = 0;
+ for (int row = top_left.first; row <= bottom_right.first; ++row) {
+ for (int column = top_left.second; column <= bottom_right.second; ++column) {
+ const int model_row = getModelRow(row);
+ const int model_column = getModelColumn(column);
+ const SpreadKey key {model_row, model_column};
+ const QVariant value = m_dataModel.getData(key, spread::Role::Display);
+ if (value.isNull())
+ continue;
+ bool is_double = false;
+ const double d = value.toDouble(&is_double);
+ if (is_double)
+ sum += d;
+ else
+ return "#ERROR!";
+ }
+ }
+ return QString::number(sum);
+ }
+ default:
+ break;
+ }
+ return QString{};
+}
+
+int SpreadModel::getViewColumn(int modelColumn) const
+{
+ auto it = m_viewColumns.find(modelColumn);
+ return (it != m_viewColumns.end()) ? it.value() : modelColumn;
+}
+
+int SpreadModel::getModelColumn(int viewColumn) const
+{
+ auto find_view_column = [viewColumn](const auto &item) {
+ return item == viewColumn;
+ };
+ auto it = std::find_if(m_viewColumns.begin(), m_viewColumns.end(), find_view_column);
+ return it != m_viewColumns.end() ? it.key() : viewColumn;
+}
+
+int SpreadModel::getViewRow(int modelRow) const
+{
+ auto it = m_viewRows.find(modelRow);
+ return (it != m_viewRows.end()) ? it.value() : modelRow;
+}
+
+int SpreadModel::getModelRow(int viewRow) const
+{
+ auto find_view_row = [viewRow](const auto &item){
+ return item == viewRow;
+ };
+ auto it = std::find_if(m_viewRows.begin(), m_viewRows.end(), find_view_row);
+ return (it != m_viewRows.end()) ? it.key() : viewRow;
+}
+
+void SpreadSelectionModel::toggleColumn(int column)
+{
+ isColumnSelected(column) ? deselectColumn(column) : selectColumn(column, false);
+}
+
+void SpreadSelectionModel::deselectColumn(int column)
+{
+ const QAbstractItemModel *model = this->model();
+ const QModelIndex first = model->index(0, column);
+ const QModelIndex last = model->index(model->rowCount() - 1, column);
+ QModelIndexList selectedRows = this->selectedRows(column);
+ if (selectedRows.empty()) {
+ select(QItemSelection{first, last}, SelectionFlag::Deselect);
+ return;
+ }
+
+ auto topToBottom = [](const QModelIndex &lhs, const QModelIndex &rhs) -> bool
+ {
+ return lhs.row() < rhs.row();
+ };
+ std::sort(selectedRows.begin(), selectedRows.end(), topToBottom);
+
+ QModelIndex index = first;
+ for (const QModelIndex &selectedRow : selectedRows) {
+ if (index.row() < selectedRow.row())
+ select(QItemSelection{index, model->index(selectedRow.row() - 1, column)},
+ SelectionFlag::Deselect);
+ index = model->index(selectedRow.row() + 1, column);
+ }
+ if (index.row() <= last.row())
+ select(QItemSelection{index, last}, SelectionFlag::Deselect);
+}
+
+void SpreadSelectionModel::selectColumn(int column, bool clear)
+{
+ if (clear)
+ this->clear();
+ const QAbstractItemModel *model = this->model();
+ const QModelIndex first = model->index(0, column);
+ const QModelIndex last = model->index(model->rowCount() - 1, column);
+ select(QItemSelection{first, last}, SelectionFlag::Select);
+}
+
+void SpreadSelectionModel::toggleRow(int row)
+{
+ isRowSelected(row) ? deselectRow(row) : selectRow(row, false);
+}
+
+void SpreadSelectionModel::deselectRow(int row)
+{
+ const QAbstractItemModel *model = this->model();
+ const QModelIndex first = model->index(row, 0);
+ const QModelIndex last = model->index(row, model->columnCount() - 1);
+ QModelIndexList selectedColumns = this->selectedColumns(row);
+ if (selectedColumns.empty()) {
+ select(QItemSelection{first, last}, SelectionFlag::Deselect);
+ return;
+ }
+
+ auto leftToRight = [](const QModelIndex &lhs, const QModelIndex &rhs) -> bool
+ {
+ return lhs.column() < rhs.column();
+ };
+ std::sort(selectedColumns.begin(), selectedColumns.end(), leftToRight);
+
+ QModelIndex index = first;
+ for (const QModelIndex &selectedColumn : selectedColumns) {
+ if (index.column() < selectedColumn.column())
+ select(QItemSelection{index, model->index(row, selectedColumn.column() - 1)},
+ SelectionFlag::Deselect);
+ index = model->index(row, selectedColumn.column() + 1);
+ }
+ if (index.column() <= last.column())
+ select(QItemSelection{index, last}, SelectionFlag::Deselect);
+}
+
+void SpreadSelectionModel::selectRow(int row, bool clear)
+{
+ if (clear)
+ this->clear();
+ const QAbstractItemModel *model = this->model();
+ const QModelIndex first = model->index(row, 0);
+ const QModelIndex last = model->index(row, model->columnCount() - 1);
+ select(QItemSelection{first, last}, SelectionFlag::Select);
+}
+
+void SpreadSelectionModel::setBehavior(Behavior behavior)
+{
+ if (behavior == m_behavior)
+ return;
+ m_behavior = behavior;
+ emit behaviorChanged();
+}
+
+void HeaderSelectionModel::setCurrent(int current)
+{
+ switch (m_orientation) {
+ case Qt::Horizontal:
+ QItemSelectionModel::setCurrentIndex(model()->index(0, current), SelectionFlag::Current);
+ break;
+ case Qt::Vertical:
+ QItemSelectionModel::setCurrentIndex(model()->index(current, 0), SelectionFlag::Current);
+ break;
+ default:
+ break;
+ }
+}
+
+void HeaderSelectionModel::setSelectionModel(SpreadSelectionModel *selectionModel)
+{
+ if (selectionModel == m_selectionModel)
+ return;
+ if (m_selectionModel)
+ disconnect(m_selectionModel);
+ m_selectionModel = selectionModel;
+ if (m_selectionModel)
+ connect(m_selectionModel, &SpreadSelectionModel::selectionChanged, this,
+ &HeaderSelectionModel::onSelectionChanged);
+ emit selectionModelChanged();
+}
+
+void HeaderSelectionModel::setOrientation(Qt::Orientation orientation)
+{
+ if (orientation == m_orientation)
+ return;
+ m_orientation = orientation;
+ emit orientationChanged();
+}
+
+void HeaderSelectionModel::onSelectionChanged(const QItemSelection &selected,
+ const QItemSelection &deselected)
+{
+ const QAbstractItemModel *model = this->model();
+ for (const QModelIndex &index : selected.indexes()) {
+ switch (m_orientation) {
+ case Qt::Horizontal:
+ if (m_selectionModel->isColumnSelected(index.column()))
+ select(model->index(0, index.column()), SelectionFlag::Select);
+ break;
+ case Qt::Vertical:
+ if (m_selectionModel->isRowSelected(index.row()))
+ select(model->index(index.row(), 0), SelectionFlag::Select);
+ break;
+ }
+ }
+ for (const QModelIndex &index : deselected.indexes()) {
+ switch (m_orientation) {
+ case Qt::Horizontal:
+ if (!m_selectionModel->isColumnSelected(index.column()))
+ select(model->index(0, index.column()), SelectionFlag::Deselect);
+ break;
+ case Qt::Vertical:
+ if (!m_selectionModel->isRowSelected(index.row()))
+ select(model->index(index.row(), 0), SelectionFlag::Deselect);
+ break;
+ }
+ }
+}
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/spreadmodel.h b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadmodel.h
new file mode 100644
index 0000000000..4ef4cd176c
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadmodel.h
@@ -0,0 +1,154 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SPREADMODEL_H
+#define SPREADMODEL_H
+
+#include "datamodel.h"
+#include "spreadformula.h"
+
+#include <QQmlEngine>
+#include <QAbstractTableModel>
+#include <QItemSelectionModel>
+#include <QMutex>
+
+
+class DataModel;
+class SpreadModel;
+
+class SpreadModel final : public QAbstractTableModel
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+ Q_DISABLE_COPY_MOVE(SpreadModel)
+
+ friend class SpreadSelectionModel;
+ friend class SpreadCell;
+ friend struct Formula;
+
+protected:
+ explicit SpreadModel(QObject *parent = nullptr) : QAbstractTableModel(parent) { }
+
+public:
+ int rowCount() const { return rowCount(QModelIndex{}); }
+ int columnCount() const { return columnCount(QModelIndex{}); }
+
+ const DataModel *dataModel() { return &m_dataModel; }
+
+ int columnNumberFromName(const QString &text);
+ int rowNumberFromName(const QString &text);
+ // returns nullptr if it's not been created yet.
+ static SpreadModel *instance();
+ static SpreadModel *create(QQmlEngine *, QJSEngine *);
+
+protected:
+ Q_INVOKABLE void update(int row, int column);
+ Q_INVOKABLE void clearHighlight();
+ Q_INVOKABLE void setHighlight(const QModelIndex &index, bool highlight);
+ Q_INVOKABLE bool clearItemData(const QModelIndexList &indexes);
+ Q_INVOKABLE bool removeColumns(QModelIndexList indexes);
+ Q_INVOKABLE bool removeRows(QModelIndexList indexes);
+ Q_INVOKABLE void mapColumn(int model, int view);
+ Q_INVOKABLE void mapRow(int model, int view);
+ Q_INVOKABLE void resetColumnMapping() { m_viewColumns.clear(); }
+ Q_INVOKABLE void resetRowMapping() { m_viewRows.clear(); }
+
+ // QAbstractItemModel interface
+ int rowCount(const QModelIndex &parent) const override;
+ int columnCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+ Q_INVOKABLE bool clearItemData(const QModelIndex &index) override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ QHash<int, QByteArray> roleNames() const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
+ bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex{}) override;
+ bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex{}) override;
+ bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex{}) override;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex{}) override;
+
+private:
+ Formula parseFormulaString(const QString &text);
+ QString formulaValueText(const Formula &formula);
+ int getViewColumn(int modelColumn) const;
+ int getModelColumn(int viewColumn) const;
+ int getViewRow(int modelRow) const;
+ int getModelRow(int viewRow) const;
+
+private:
+ std::pair<int, int> m_size {1000, 26}; // rows:1-1000, columns:A-Z
+ DataModel m_dataModel;
+ QMap<int, int> m_viewColumns;
+ QMap<int, int> m_viewRows;
+ QMutex m_updateMutex;
+ static inline SpreadModel *s_instance {nullptr};
+};
+
+class SpreadSelectionModel : public QItemSelectionModel
+{
+ Q_OBJECT
+ QML_ELEMENT
+
+ Q_PROPERTY(Behavior behavior READ getBehavior WRITE setBehavior NOTIFY behaviorChanged FINAL)
+
+public:
+ enum Behavior {
+ DisabledBehavior,
+ SelectCells,
+ SelectColumns,
+ SelectRows,
+ };
+ Q_ENUM(Behavior)
+
+public:
+ Q_INVOKABLE void toggleColumn(int column);
+ Q_INVOKABLE void deselectColumn(int column);
+ Q_INVOKABLE void selectColumn(int column, bool clear = true);
+ Q_INVOKABLE void toggleRow(int row);
+ Q_INVOKABLE void deselectRow(int row);
+ Q_INVOKABLE void selectRow(int row, bool clear = true);
+
+protected:
+ Behavior getBehavior() const { return m_behavior; }
+
+protected slots:
+ void setBehavior(Behavior);
+
+signals:
+ void behaviorChanged();
+
+private:
+ Behavior m_behavior = Behavior::DisabledBehavior;
+};
+
+class HeaderSelectionModel : public QItemSelectionModel
+{
+ Q_OBJECT
+ QML_ELEMENT
+
+ Q_PROPERTY(SpreadSelectionModel* selectionModel READ getSelectionModel WRITE setSelectionModel NOTIFY selectionModelChanged FINAL)
+ Q_PROPERTY(Qt::Orientation orientation READ getOrientation WRITE setOrientation NOTIFY orientationChanged FINAL)
+
+protected:
+ Q_INVOKABLE void setCurrent(int current = -1);
+ SpreadSelectionModel *getSelectionModel() { return m_selectionModel; }
+ Qt::Orientation getOrientation() const { return m_orientation; }
+
+protected slots:
+ void setSelectionModel(SpreadSelectionModel *selectionModel);
+ void setOrientation(Qt::Orientation orientation);
+
+private slots:
+ void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
+
+signals:
+ void selectionModelChanged();
+ void orientationChanged();
+
+private:
+ SpreadSelectionModel *m_selectionModel = nullptr;
+ Qt::Orientation m_orientation = Qt::Horizontal;
+};
+
+#endif // SPREADMODEL_H
diff --git a/examples/quickcontrols/spreadsheets/Spreadsheets/spreadrole.h b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadrole.h
new file mode 100644
index 0000000000..aa1c69138a
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/Spreadsheets/spreadrole.h
@@ -0,0 +1,23 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef SPREADROLE_H
+#define SPREADROLE_H
+
+#include <Qt>
+
+namespace spread {
+enum Role {
+ // data roles
+ BeginRole = Qt::DisplayRole, // begin of data roles
+ Display = Qt::DisplayRole,
+ Edit = Qt::EditRole,
+ Hightlight = Qt::UserRole + 1,
+ EndRole, // end of data roles
+ // non-data roles
+ ColumnName,
+ RowName,
+};
+}
+
+#endif // SPREADROLE_H
diff --git a/examples/quickcontrols/spreadsheets/main.cpp b/examples/quickcontrols/spreadsheets/main.cpp
new file mode 100644
index 0000000000..5c8b46e326
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/main.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QIcon>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ QObject::connect(
+ &engine,
+ &QQmlApplicationEngine::objectCreationFailed,
+ &app,
+ []() { QCoreApplication::exit(-1); },
+ Qt::QueuedConnection);
+ engine.loadFromModule("Spreadsheets", "Main");
+
+ app.setWindowIcon(QIcon{":/qt/examples/spreadsheet/icons/spreadsheet.svg"});
+
+ return app.exec();
+}
diff --git a/examples/quickcontrols/spreadsheets/spreadsheet.svg b/examples/quickcontrols/spreadsheets/spreadsheet.svg
new file mode 100644
index 0000000000..cc13cbb907
--- /dev/null
+++ b/examples/quickcontrols/spreadsheets/spreadsheet.svg
@@ -0,0 +1,32 @@
+<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect y="8" width="64" height="44" fill="#989898"/>
+<path d="M2 11.1111C2 10.4975 2.49746 10 3.11111 10H5.88889C6.50254 10 7 10.4975 7 11.1111V13.8889C7 14.5025 6.50254 15 5.88889 15H3.11111C2.49746 15 2 14.5025 2 13.8889V11.1111Z" fill="#0F0F0F"/>
+<path d="M9 11.1111C9 10.4975 9 10 10.0234 10H61.0185C62 10 62 10.4975 62 11.1111V13.8889C62 14.5025 62 15 61.0185 15H9.98148C9 15 9 14.5025 9 13.8889V11.1111Z" fill="#0D0D0D"/>
+<path d="M9 11.1111C9 10.4975 9 10 10.0234 10H61.0185C62 10 62 10.4975 62 11.1111V13.8889C62 14.5025 62 15 61.0185 15H9.98148C9 15 9 14.5025 9 13.8889V11.1111Z" fill="#0D0D0D"/>
+<path d="M3.11111 50C2.49746 50 2 50 2 49.3628L2 17.6111C2 17 2.49746 17 3.11111 17H5.88889C6.50254 17 7 17 7 17.6111L7 49.3889C7 50 6.50254 50 5.88889 50H3.11111Z" fill="#0D0D0D"/>
+<path d="M9.75 17.5H17.25C17.3864 17.5 17.4384 17.5232 17.4484 17.5285C17.4486 17.5287 17.4488 17.5288 17.449 17.5289C17.4499 17.5304 17.4513 17.533 17.4531 17.5367C17.4646 17.5615 17.4808 17.6153 17.4902 17.7225C17.4996 17.8293 17.5 17.9523 17.5 18.1111V20.8889C17.5 21.0477 17.4996 21.1707 17.4902 21.2775C17.4808 21.3847 17.4646 21.4385 17.4531 21.4633C17.4513 21.467 17.4499 21.4696 17.449 21.4711C17.4488 21.4712 17.4486 21.4713 17.4484 21.4715C17.4384 21.4768 17.3864 21.5 17.25 21.5H9.75C9.61364 21.5 9.56161 21.4768 9.55162 21.4715C9.5514 21.4713 9.5512 21.4712 9.55101 21.4711C9.55007 21.4696 9.54867 21.467 9.54691 21.4633C9.53536 21.4385 9.51924 21.3847 9.50979 21.2775C9.50037 21.1707 9.5 21.0477 9.5 20.8889V17.8333C9.5 17.6813 9.50057 17.5858 9.50723 17.5137C9.55683 17.5062 9.63379 17.5 9.75 17.5Z" stroke="black"/>
+<path d="M31.75 17.5H39.25C39.3864 17.5 39.4384 17.5232 39.4484 17.5285C39.4486 17.5287 39.4488 17.5288 39.449 17.5289C39.4499 17.5304 39.4513 17.533 39.4531 17.5367C39.4646 17.5615 39.4808 17.6153 39.4902 17.7225C39.4996 17.8293 39.5 17.9523 39.5 18.1111V20.8889C39.5 21.0477 39.4996 21.1707 39.4902 21.2775C39.4808 21.3847 39.4646 21.4385 39.4531 21.4633C39.4513 21.467 39.4499 21.4696 39.449 21.4711C39.4488 21.4712 39.4486 21.4713 39.4484 21.4715C39.4384 21.4768 39.3864 21.5 39.25 21.5H31.75C31.6136 21.5 31.5616 21.4768 31.5516 21.4715C31.5514 21.4713 31.5512 21.4712 31.551 21.4711C31.5501 21.4696 31.5487 21.467 31.5469 21.4633C31.5354 21.4385 31.5192 21.3847 31.5098 21.2775C31.5004 21.1707 31.5 21.0477 31.5 20.8889V17.8333C31.5 17.6813 31.5006 17.5858 31.5072 17.5137C31.5568 17.5062 31.6338 17.5 31.75 17.5Z" stroke="black"/>
+<path d="M42.75 17.5H50.25C50.3864 17.5 50.4384 17.5232 50.4484 17.5285C50.4486 17.5287 50.4488 17.5288 50.449 17.5289C50.4499 17.5304 50.4513 17.533 50.4531 17.5367C50.4646 17.5615 50.4808 17.6153 50.4902 17.7225C50.4996 17.8293 50.5 17.9523 50.5 18.1111V20.8889C50.5 21.0477 50.4996 21.1707 50.4902 21.2775C50.4808 21.3847 50.4646 21.4385 50.4531 21.4633C50.4513 21.467 50.4499 21.4696 50.449 21.4711C50.4488 21.4712 50.4486 21.4713 50.4484 21.4715C50.4384 21.4768 50.3864 21.5 50.25 21.5H42.75C42.6136 21.5 42.5616 21.4768 42.5516 21.4715C42.5514 21.4713 42.5512 21.4712 42.551 21.4711C42.5501 21.4696 42.5487 21.467 42.5469 21.4633C42.5354 21.4385 42.5192 21.3847 42.5098 21.2775C42.5004 21.1707 42.5 21.0477 42.5 20.8889V17.8333C42.5 17.6813 42.5006 17.5858 42.5072 17.5137C42.5568 17.5062 42.6338 17.5 42.75 17.5Z" stroke="black"/>
+<path d="M53.75 17.5H61.25C61.3864 17.5 61.4384 17.5232 61.4484 17.5285C61.4486 17.5287 61.4488 17.5288 61.449 17.5289C61.4499 17.5304 61.4513 17.533 61.4531 17.5367C61.4646 17.5615 61.4808 17.6153 61.4902 17.7225C61.4996 17.8293 61.5 17.9523 61.5 18.1111V20.8889C61.5 21.0477 61.4996 21.1707 61.4902 21.2775C61.4808 21.3847 61.4646 21.4385 61.4531 21.4633C61.4513 21.467 61.4499 21.4696 61.449 21.4711C61.4488 21.4712 61.4486 21.4713 61.4484 21.4715C61.4384 21.4768 61.3864 21.5 61.25 21.5H53.75C53.6136 21.5 53.5616 21.4768 53.5516 21.4715C53.5514 21.4713 53.5512 21.4712 53.551 21.4711C53.5501 21.4696 53.5487 21.467 53.5469 21.4633C53.5354 21.4385 53.5192 21.3847 53.5098 21.2775C53.5004 21.1707 53.5 21.0477 53.5 20.8889V17.8333C53.5 17.6813 53.5006 17.5858 53.5072 17.5137C53.5568 17.5062 53.6338 17.5 53.75 17.5Z" stroke="black"/>
+<path d="M9.75 38.5H17.25C17.3864 38.5 17.4384 38.5232 17.4484 38.5285C17.4486 38.5287 17.4488 38.5288 17.449 38.5289C17.4499 38.5304 17.4513 38.533 17.4531 38.5367C17.4646 38.5615 17.4808 38.6153 17.4902 38.7225C17.4996 38.8293 17.5 38.9523 17.5 39.1111V41.8889C17.5 42.0477 17.4996 42.1707 17.4902 42.2775C17.4808 42.3847 17.4646 42.4385 17.4531 42.4633C17.4513 42.467 17.4499 42.4696 17.449 42.4711C17.4488 42.4712 17.4486 42.4713 17.4484 42.4715C17.4384 42.4768 17.3864 42.5 17.25 42.5H9.75C9.61364 42.5 9.56161 42.4768 9.55162 42.4715C9.5514 42.4713 9.5512 42.4712 9.55101 42.4711C9.55007 42.4696 9.54867 42.467 9.54691 42.4633C9.53536 42.4385 9.51924 42.3847 9.50979 42.2775C9.50037 42.1707 9.5 42.0477 9.5 41.8889V38.8333C9.5 38.6813 9.50057 38.5858 9.50723 38.5137C9.55683 38.5062 9.63379 38.5 9.75 38.5Z" stroke="black"/>
+<path d="M31.75 38.5H39.25C39.3864 38.5 39.4384 38.5232 39.4484 38.5285C39.4486 38.5287 39.4488 38.5288 39.449 38.5289C39.4499 38.5304 39.4513 38.533 39.4531 38.5367C39.4646 38.5615 39.4808 38.6153 39.4902 38.7225C39.4996 38.8293 39.5 38.9523 39.5 39.1111V41.8889C39.5 42.0477 39.4996 42.1707 39.4902 42.2775C39.4808 42.3847 39.4646 42.4385 39.4531 42.4633C39.4513 42.467 39.4499 42.4696 39.449 42.4711C39.4488 42.4712 39.4486 42.4713 39.4484 42.4715C39.4384 42.4768 39.3864 42.5 39.25 42.5H31.75C31.6136 42.5 31.5616 42.4768 31.5516 42.4715C31.5514 42.4713 31.5512 42.4712 31.551 42.4711C31.5501 42.4696 31.5487 42.467 31.5469 42.4633C31.5354 42.4385 31.5192 42.3847 31.5098 42.2775C31.5004 42.1707 31.5 42.0477 31.5 41.8889V38.8333C31.5 38.6813 31.5006 38.5858 31.5072 38.5137C31.5568 38.5062 31.6338 38.5 31.75 38.5Z" stroke="black"/>
+<path d="M42.75 38.5H50.25C50.3864 38.5 50.4384 38.5232 50.4484 38.5285C50.4486 38.5287 50.4488 38.5288 50.449 38.5289C50.4499 38.5304 50.4513 38.533 50.4531 38.5367C50.4646 38.5615 50.4808 38.6153 50.4902 38.7225C50.4996 38.8293 50.5 38.9523 50.5 39.1111V41.8889C50.5 42.0477 50.4996 42.1707 50.4902 42.2775C50.4808 42.3847 50.4646 42.4385 50.4531 42.4633C50.4513 42.467 50.4499 42.4696 50.449 42.4711C50.4488 42.4712 50.4486 42.4713 50.4484 42.4715C50.4384 42.4768 50.3864 42.5 50.25 42.5H42.75C42.6136 42.5 42.5616 42.4768 42.5516 42.4715C42.5514 42.4713 42.5512 42.4712 42.551 42.4711C42.5501 42.4696 42.5487 42.467 42.5469 42.4633C42.5354 42.4385 42.5192 42.3847 42.5098 42.2775C42.5004 42.1707 42.5 42.0477 42.5 41.8889V38.8333C42.5 38.6813 42.5006 38.5858 42.5072 38.5137C42.5568 38.5062 42.6338 38.5 42.75 38.5Z" stroke="black"/>
+<path d="M53.75 38.5H61.25C61.3864 38.5 61.4384 38.5232 61.4484 38.5285C61.4486 38.5287 61.4488 38.5288 61.449 38.5289C61.4499 38.5304 61.4513 38.533 61.4531 38.5367C61.4646 38.5615 61.4808 38.6153 61.4902 38.7225C61.4996 38.8293 61.5 38.9523 61.5 39.1111V41.8889C61.5 42.0477 61.4996 42.1707 61.4902 42.2775C61.4808 42.3847 61.4646 42.4385 61.4531 42.4633C61.4513 42.467 61.4499 42.4696 61.449 42.4711C61.4488 42.4712 61.4486 42.4713 61.4484 42.4715C61.4384 42.4768 61.3864 42.5 61.25 42.5H53.75C53.6136 42.5 53.5616 42.4768 53.5516 42.4715C53.5514 42.4713 53.5512 42.4712 53.551 42.4711C53.5501 42.4696 53.5487 42.467 53.5469 42.4633C53.5354 42.4385 53.5192 42.3847 53.5098 42.2775C53.5004 42.1707 53.5 42.0477 53.5 41.8889V38.8333C53.5 38.6813 53.5006 38.5858 53.5072 38.5137C53.5568 38.5062 53.6338 38.5 53.75 38.5Z" stroke="black"/>
+<path d="M9.75 24.5H17.25C17.3864 24.5 17.4384 24.5232 17.4484 24.5285C17.4486 24.5287 17.4488 24.5288 17.449 24.5289C17.4499 24.5304 17.4513 24.533 17.4531 24.5367C17.4646 24.5615 17.4808 24.6153 17.4902 24.7225C17.4996 24.8293 17.5 24.9523 17.5 25.1111V27.8889C17.5 28.0477 17.4996 28.1707 17.4902 28.2775C17.4808 28.3847 17.4646 28.4385 17.4531 28.4633C17.4513 28.467 17.4499 28.4696 17.449 28.4711C17.4488 28.4712 17.4486 28.4713 17.4484 28.4715C17.4384 28.4768 17.3864 28.5 17.25 28.5H9.75C9.61364 28.5 9.56161 28.4768 9.55162 28.4715C9.5514 28.4713 9.5512 28.4712 9.55101 28.4711C9.55007 28.4696 9.54867 28.467 9.54691 28.4633C9.53536 28.4385 9.51924 28.3847 9.50979 28.2775C9.50037 28.1707 9.5 28.0477 9.5 27.8889V24.8333C9.5 24.6813 9.50057 24.5858 9.50723 24.5137C9.55683 24.5062 9.63379 24.5 9.75 24.5Z" stroke="black"/>
+<path d="M31.75 24.5H39.25C39.3864 24.5 39.4384 24.5232 39.4484 24.5285C39.4486 24.5287 39.4488 24.5288 39.449 24.5289C39.4499 24.5304 39.4513 24.533 39.4531 24.5367C39.4646 24.5615 39.4808 24.6153 39.4902 24.7225C39.4996 24.8293 39.5 24.9523 39.5 25.1111V27.8889C39.5 28.0477 39.4996 28.1707 39.4902 28.2775C39.4808 28.3847 39.4646 28.4385 39.4531 28.4633C39.4513 28.467 39.4499 28.4696 39.449 28.4711C39.4488 28.4712 39.4486 28.4713 39.4484 28.4715C39.4384 28.4768 39.3864 28.5 39.25 28.5H31.75C31.6136 28.5 31.5616 28.4768 31.5516 28.4715C31.5514 28.4713 31.5512 28.4712 31.551 28.4711C31.5501 28.4696 31.5487 28.467 31.5469 28.4633C31.5354 28.4385 31.5192 28.3847 31.5098 28.2775C31.5004 28.1707 31.5 28.0477 31.5 27.8889V24.8333C31.5 24.6813 31.5006 24.5858 31.5072 24.5137C31.5568 24.5062 31.6338 24.5 31.75 24.5Z" stroke="black"/>
+<path d="M42.75 24.5H50.25C50.3864 24.5 50.4384 24.5232 50.4484 24.5285C50.4486 24.5287 50.4488 24.5288 50.449 24.5289C50.4499 24.5304 50.4513 24.533 50.4531 24.5367C50.4646 24.5615 50.4808 24.6153 50.4902 24.7225C50.4996 24.8293 50.5 24.9523 50.5 25.1111V27.8889C50.5 28.0477 50.4996 28.1707 50.4902 28.2775C50.4808 28.3847 50.4646 28.4385 50.4531 28.4633C50.4513 28.467 50.4499 28.4696 50.449 28.4711C50.4488 28.4712 50.4486 28.4713 50.4484 28.4715C50.4384 28.4768 50.3864 28.5 50.25 28.5H42.75C42.6136 28.5 42.5616 28.4768 42.5516 28.4715C42.5514 28.4713 42.5512 28.4712 42.551 28.4711C42.5501 28.4696 42.5487 28.467 42.5469 28.4633C42.5354 28.4385 42.5192 28.3847 42.5098 28.2775C42.5004 28.1707 42.5 28.0477 42.5 27.8889V24.8333C42.5 24.6813 42.5006 24.5858 42.5072 24.5137C42.5568 24.5062 42.6338 24.5 42.75 24.5Z" stroke="black"/>
+<path d="M53.75 24.5H61.25C61.3864 24.5 61.4384 24.5232 61.4484 24.5285C61.4486 24.5287 61.4488 24.5288 61.449 24.5289C61.4499 24.5304 61.4513 24.533 61.4531 24.5367C61.4646 24.5615 61.4808 24.6153 61.4902 24.7225C61.4996 24.8293 61.5 24.9523 61.5 25.1111V27.8889C61.5 28.0477 61.4996 28.1707 61.4902 28.2775C61.4808 28.3847 61.4646 28.4385 61.4531 28.4633C61.4513 28.467 61.4499 28.4696 61.449 28.4711C61.4488 28.4712 61.4486 28.4713 61.4484 28.4715C61.4384 28.4768 61.3864 28.5 61.25 28.5H53.75C53.6136 28.5 53.5616 28.4768 53.5516 28.4715C53.5514 28.4713 53.5512 28.4712 53.551 28.4711C53.5501 28.4696 53.5487 28.467 53.5469 28.4633C53.5354 28.4385 53.5192 28.3847 53.5098 28.2775C53.5004 28.1707 53.5 28.0477 53.5 27.8889V24.8333C53.5 24.6813 53.5006 24.5858 53.5072 24.5137C53.5568 24.5062 53.6338 24.5 53.75 24.5Z" stroke="black"/>
+<path d="M9.75 45.5H17.25C17.3864 45.5 17.4384 45.5232 17.4484 45.5285C17.4486 45.5287 17.4488 45.5288 17.449 45.5289C17.4499 45.5304 17.4513 45.533 17.4531 45.5367C17.4646 45.5615 17.4808 45.6153 17.4902 45.7225C17.4996 45.8293 17.5 45.9523 17.5 46.1111V48.8889C17.5 49.0477 17.4996 49.1707 17.4902 49.2775C17.4808 49.3847 17.4646 49.4385 17.4531 49.4633C17.4513 49.467 17.4499 49.4696 17.449 49.4711C17.4488 49.4712 17.4486 49.4713 17.4484 49.4715C17.4384 49.4768 17.3864 49.5 17.25 49.5H9.75C9.61364 49.5 9.56161 49.4768 9.55162 49.4715C9.5514 49.4713 9.5512 49.4712 9.55101 49.4711C9.55007 49.4696 9.54867 49.467 9.54691 49.4633C9.53536 49.4385 9.51924 49.3847 9.50979 49.2775C9.50037 49.1707 9.5 49.0477 9.5 48.8889V45.8333C9.5 45.6813 9.50057 45.5858 9.50723 45.5137C9.55683 45.5062 9.63379 45.5 9.75 45.5Z" stroke="black"/>
+<path d="M31.75 45.5H39.25C39.3864 45.5 39.4384 45.5232 39.4484 45.5285C39.4486 45.5287 39.4488 45.5288 39.449 45.5289C39.4499 45.5304 39.4513 45.533 39.4531 45.5367C39.4646 45.5615 39.4808 45.6153 39.4902 45.7225C39.4996 45.8293 39.5 45.9523 39.5 46.1111V48.8889C39.5 49.0477 39.4996 49.1707 39.4902 49.2775C39.4808 49.3847 39.4646 49.4385 39.4531 49.4633C39.4513 49.467 39.4499 49.4696 39.449 49.4711C39.4488 49.4712 39.4486 49.4713 39.4484 49.4715C39.4384 49.4768 39.3864 49.5 39.25 49.5H31.75C31.6136 49.5 31.5616 49.4768 31.5516 49.4715C31.5514 49.4713 31.5512 49.4712 31.551 49.4711C31.5501 49.4696 31.5487 49.467 31.5469 49.4633C31.5354 49.4385 31.5192 49.3847 31.5098 49.2775C31.5004 49.1707 31.5 49.0477 31.5 48.8889V45.8333C31.5 45.6813 31.5006 45.5858 31.5072 45.5137C31.5568 45.5062 31.6338 45.5 31.75 45.5Z" stroke="black"/>
+<path d="M42.75 45.5H50.25C50.3864 45.5 50.4384 45.5232 50.4484 45.5285C50.4486 45.5287 50.4488 45.5288 50.449 45.5289C50.4499 45.5304 50.4513 45.533 50.4531 45.5367C50.4646 45.5615 50.4808 45.6153 50.4902 45.7225C50.4996 45.8293 50.5 45.9523 50.5 46.1111V48.8889C50.5 49.0477 50.4996 49.1707 50.4902 49.2775C50.4808 49.3847 50.4646 49.4385 50.4531 49.4633C50.4513 49.467 50.4499 49.4696 50.449 49.4711C50.4488 49.4712 50.4486 49.4713 50.4484 49.4715C50.4384 49.4768 50.3864 49.5 50.25 49.5H42.75C42.6136 49.5 42.5616 49.4768 42.5516 49.4715C42.5514 49.4713 42.5512 49.4712 42.551 49.4711C42.5501 49.4696 42.5487 49.467 42.5469 49.4633C42.5354 49.4385 42.5192 49.3847 42.5098 49.2775C42.5004 49.1707 42.5 49.0477 42.5 48.8889V45.8333C42.5 45.6813 42.5006 45.5858 42.5072 45.5137C42.5568 45.5062 42.6338 45.5 42.75 45.5Z" stroke="black"/>
+<path d="M53.75 45.5H61.25C61.3864 45.5 61.4384 45.5232 61.4484 45.5285C61.4486 45.5287 61.4488 45.5288 61.449 45.5289C61.4499 45.5304 61.4513 45.533 61.4531 45.5367C61.4646 45.5615 61.4808 45.6153 61.4902 45.7225C61.4996 45.8293 61.5 45.9523 61.5 46.1111V48.8889C61.5 49.0477 61.4996 49.1707 61.4902 49.2775C61.4808 49.3847 61.4646 49.4385 61.4531 49.4633C61.4513 49.467 61.4499 49.4696 61.449 49.4711C61.4488 49.4712 61.4486 49.4713 61.4484 49.4715C61.4384 49.4768 61.3864 49.5 61.25 49.5H53.75C53.6136 49.5 53.5616 49.4768 53.5516 49.4715C53.5514 49.4713 53.5512 49.4712 53.551 49.4711C53.5501 49.4696 53.5487 49.467 53.5469 49.4633C53.5354 49.4385 53.5192 49.3847 53.5098 49.2775C53.5004 49.1707 53.5 49.0477 53.5 48.8889V45.8333C53.5 45.6813 53.5006 45.5858 53.5072 45.5137C53.5568 45.5062 53.6338 45.5 53.75 45.5Z" stroke="black"/>
+<path d="M20 18.1111C20 17.4975 20 17 20.75 17H28.25C29 17 29 17.4975 29 18.1111V20.8889C29 21.5025 29 22 28.25 22H20.75C20 22 20 21.5025 20 20.8889V18.1111Z" fill="#0D0D0D"/>
+<path d="M20 39.1111C20 38.4975 20 38 20.75 38H28.25C29 38 29 38.4975 29 39.1111V41.8889C29 42.5025 29 43 28.25 43H20.75C20 43 20 42.5025 20 41.8889V39.1111Z" fill="#0D0D0D"/>
+<path d="M20 25.1111C20 24.4975 20 24 20.75 24H28.25C29 24 29 24.4975 29 25.1111V27.8889C29 28.5025 29 29 28.25 29H20.75C20 29 20 28.5025 20 27.8889V25.1111Z" fill="#0D0D0D"/>
+<path d="M9 32.1111C9 31.4975 9 31 9.75 31H17.25C18 31 18 31.4975 18 32.1111V34.8889C18 35.5025 18 36 17.25 36H9.75C8.99999 36 9 35.5025 9 34.8889V32.1111Z" fill="#0D0D0D"/>
+<path d="M31 32.1111C31 31.4975 31 31 31.75 31H39.25C40 31 40 31.4975 40 32.1111V34.8889C40 35.5025 40 36 39.25 36H31.75C31 36 31 35.5025 31 34.8889V32.1111Z" fill="#0D0D0D"/>
+<path d="M20 32.1111C20 31.4975 20 31 20.75 31H28.25C29 31 29 31.4975 29 32.1111V34.8889C29 35.5025 29 36 28.25 36H20.75C20 36 20 35.5025 20 34.8889V32.1111Z" fill="#0D0D0D"/>
+<path d="M20 46.1111C20 45.4975 20 45 20.75 45H28.25C29 45 29 45.4975 29 46.1111V48.8889C29 49.5025 29 50 28.25 50H20.75C20 50 20 49.5025 20 48.8889V46.1111Z" fill="#0D0D0D"/>
+<path d="M42 32.1111C42 31.4975 42 31 42.75 31H50.25C51 31 51 31.4975 51 32.1111V34.8889C51 35.5025 51 36 50.25 36H42.75C42 36 42 35.5025 42 34.8889V32.1111Z" fill="#0D0D0D"/>
+<path d="M53 32.1111C53 31.4975 53 31 53.75 31H61.25C62 31 62 31.4975 62 32.1111V34.8889C62 35.5025 62 36 61.25 36H53.75C53 36 53 35.5025 53 34.8889V32.1111Z" fill="#0D0D0D"/>
+</svg>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ca83200cf5..56992dda9b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -95,6 +95,7 @@ add_subdirectory(qmldom)
# Build qmlcachegen now, so that we can use it in src/imports.
if(QT_FEATURE_xmlstreamwriter)
+ add_subdirectory(../tools/qmlaotstats qmlaotstats)
add_subdirectory(../tools/qmlcachegen qmlcachegen)
endif()
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 1446f9844e..90a4c9f786 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -20,7 +20,6 @@ qt_internal_add_qml_module(QmlCore
PUBLIC_LIBRARIES
Qt::Core
Qt::Qml
- GENERATE_CPP_EXPORTS
)
qt_internal_extend_target(QmlCore CONDITION QT_FEATURE_settings
diff --git a/src/core/doc/qtqmlcore.qdocconf b/src/core/doc/qtqmlcore.qdocconf
index a20baad3f5..47722f7de3 100644
--- a/src/core/doc/qtqmlcore.qdocconf
+++ b/src/core/doc/qtqmlcore.qdocconf
@@ -1,7 +1,7 @@
include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
project = QtQmlCore
-description = Qt QML Core Reference Documentation
+description = Qt Qml Core Reference Documentation
version = $QT_VERSION
qhp.projects = QtQmlCore
@@ -9,12 +9,12 @@ qhp.projects = QtQmlCore
qhp.QtQmlCore.file = qtqmlcore.qhp
qhp.QtQmlCore.namespace = org.qt-project.qtqmlcore.$QT_VERSION_TAG
qhp.QtQmlCore.virtualFolder = qtqmlcore
-qhp.QtQmlCore.indexTitle = Qt QML Core
+qhp.QtQmlCore.indexTitle = Qt Qml Core
qhp.QtQmlCore.indexRoot =
qhp.QtQmlCore.subprojects = qmltypes
qhp.QtQmlCore.subprojects.qmltypes.title = QML Types
-qhp.QtQmlCore.subprojects.qmltypes.indexTitle = Qt QML Core QML Types
+qhp.QtQmlCore.subprojects.qmltypes.indexTitle = Qt Qml Core QML Types
qhp.QtQmlCore.subprojects.qmltypes.selectors = qmlclass
qhp.QtQmlCore.subprojects.qmltypes.sortPages = true
@@ -28,8 +28,8 @@ sourcedirs += ../
imagedirs += images
-navigation.landingpage = "Qt QML Core"
-navigation.qmltypespage = "Qt QML Core QML Types"
+navigation.landingpage = "Qt Qml Core"
+navigation.qmltypespage = "Qt Qml Core QML Types"
tagfile = qtqmlcore.tags
diff --git a/src/core/doc/src/qmlpermissions.qdoc b/src/core/doc/src/qmlpermissions.qdoc
index fab0bba0d2..72c7d23756 100644
--- a/src/core/doc/src/qmlpermissions.qdoc
+++ b/src/core/doc/src/qmlpermissions.qdoc
@@ -12,7 +12,7 @@
require explicit consent from the user before accessing these
features.
- The \l{Qt QML Core} module exposes the Qt C++
+ The \l{Qt Qml Core} module exposes the Qt C++
\l [QtCore] {Application Permissions} functionality to QML via a set of
permission types that can be used to check or request permission in a cross
platform manner.
diff --git a/src/core/doc/src/qtqmlcore-qmltypes.qdoc b/src/core/doc/src/qtqmlcore-qmltypes.qdoc
index 9136d5e0af..47349c380a 100644
--- a/src/core/doc/src/qtqmlcore-qmltypes.qdoc
+++ b/src/core/doc/src/qtqmlcore-qmltypes.qdoc
@@ -3,11 +3,11 @@
/*!
\qmlmodule QtCore
- \title Qt QML Core QML Types
+ \title Qt Qml Core QML Types
\ingroup qmlmodules
\brief Provides core system functionality in QML.
- The Qt QML Core module provides core system functionality in QML.
+ The Qt Qml Core module provides core system functionality in QML.
The QML types can be imported into your application using the
following import statement in your .qml file:
@@ -24,7 +24,7 @@
\list
\li \l {Qt Core}
- \li \l {Qt QML QML Types}{Base QML Types}
+ \li \l {Qt Qml QML Types}{Base QML Types}
\endlist
\noautolist
diff --git a/src/core/doc/src/qtqmlcore.qdoc b/src/core/doc/src/qtqmlcore.qdoc
index 2c8b0ef8b1..cf7d71727c 100644
--- a/src/core/doc/src/qtqmlcore.qdoc
+++ b/src/core/doc/src/qtqmlcore.qdoc
@@ -3,9 +3,9 @@
/*!
\page qtqmlcore-index.html
- \title Qt QML Core
+ \title Qt Qml Core
- \brief The Qt QML Core module provides core system functionality in QML.
+ \brief The Qt Qml Core module provides core system functionality in QML.
\section1 Application Permissions
diff --git a/src/core/qqmlsettings.cpp b/src/core/qqmlsettings.cpp
index 0b3bc9ebd3..463d122860 100644
--- a/src/core/qqmlsettings.cpp
+++ b/src/core/qqmlsettings.cpp
@@ -200,7 +200,7 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-Q_LOGGING_CATEGORY(lcQmlSettings, "qt.core.settings")
+Q_STATIC_LOGGING_CATEGORY(lcQmlSettings, "qt.core.settings")
static constexpr const int settingsWriteDelay = 500;
diff --git a/src/effects/CMakeLists.txt b/src/effects/CMakeLists.txt
index f461116818..85e4b3c514 100644
--- a/src/effects/CMakeLists.txt
+++ b/src/effects/CMakeLists.txt
@@ -25,7 +25,6 @@ qt_internal_add_qml_module(QuickEffectsPrivate
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
- GENERATE_CPP_EXPORTS
)
qt_internal_add_resource(QuickEffectsPrivate "effects"
diff --git a/src/effects/qquickmultieffect.cpp b/src/effects/qquickmultieffect.cpp
index 7561649fbf..bbad9794ad 100644
--- a/src/effects/qquickmultieffect.cpp
+++ b/src/effects/qquickmultieffect.cpp
@@ -8,7 +8,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQuickEffect, "qt.quick.effects")
+Q_STATIC_LOGGING_CATEGORY(lcQuickEffect, "qt.quick.effects")
/*!
\keyword Qt Quick Effects
diff --git a/src/imports/tooling/Method.qml b/src/imports/tooling/Method.qml
index cab07f6e38..c66b52406e 100644
--- a/src/imports/tooling/Method.qml
+++ b/src/imports/tooling/Method.qml
@@ -12,5 +12,5 @@ Member {
property bool isPointer: false
property bool isJavaScriptFunction: false
property bool isCloned: false
- property bool isConstant: false
+ property bool isTypeConstant: false
}
diff --git a/src/imports/tooling/Parameter.qml b/src/imports/tooling/Parameter.qml
index 0f44074284..779f6102a2 100644
--- a/src/imports/tooling/Parameter.qml
+++ b/src/imports/tooling/Parameter.qml
@@ -8,5 +8,5 @@ QtObject {
property string type
property bool isPointer: false
property bool isList: false
- property bool isConstant: false
+ property bool isTypeConstant: false
}
diff --git a/src/imports/tooling/Property.qml b/src/imports/tooling/Property.qml
index ba21db566c..f62b4ac992 100644
--- a/src/imports/tooling/Property.qml
+++ b/src/imports/tooling/Property.qml
@@ -10,7 +10,8 @@ Member {
property bool isRequired: false
property bool isList: false
property bool isFinal: false
- property bool isConstant: false
+ property bool isTypeConstant: false
+ property bool isPropertyConstant: false
property int revision: 0
property string bindable
property string read
diff --git a/src/labs/animation/CMakeLists.txt b/src/labs/animation/CMakeLists.txt
index 57fd2bb170..bf8e41b7e2 100644
--- a/src/labs/animation/CMakeLists.txt
+++ b/src/labs/animation/CMakeLists.txt
@@ -16,5 +16,4 @@ qt_internal_add_qml_module(LabsAnimation
PUBLIC_LIBRARIES
Qt::QmlPrivate
Qt::QuickPrivate
- GENERATE_CPP_EXPORTS
)
diff --git a/src/labs/animation/qquickboundaryrule.cpp b/src/labs/animation/qquickboundaryrule.cpp
index ead72be187..51bf5b5a8f 100644
--- a/src/labs/animation/qquickboundaryrule.cpp
+++ b/src/labs/animation/qquickboundaryrule.cpp
@@ -13,7 +13,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcBR, "qt.quick.boundaryrule")
+Q_STATIC_LOGGING_CATEGORY(lcBR, "qt.quick.boundaryrule")
class QQuickBoundaryReturnJob;
class QQuickBoundaryRulePrivate : public QObjectPrivate
diff --git a/src/labs/folderlistmodel/CMakeLists.txt b/src/labs/folderlistmodel/CMakeLists.txt
index bcb7b7d94f..e0851ee203 100644
--- a/src/labs/folderlistmodel/CMakeLists.txt
+++ b/src/labs/folderlistmodel/CMakeLists.txt
@@ -19,5 +19,4 @@ qt_internal_add_qml_module(LabsFolderListModel
Qt::CorePrivate
Qt::QmlPrivate
Qt::QmlModelsPrivate
- GENERATE_CPP_EXPORTS
)
diff --git a/src/labs/folderlistmodel/fileinfothread.cpp b/src/labs/folderlistmodel/fileinfothread.cpp
index 7b0bea721d..aa670338de 100644
--- a/src/labs/folderlistmodel/fileinfothread.cpp
+++ b/src/labs/folderlistmodel/fileinfothread.cpp
@@ -11,7 +11,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcFileInfoThread, "qt.labs.folderlistmodel.fileinfothread")
+Q_STATIC_LOGGING_CATEGORY(lcFileInfoThread, "qt.labs.folderlistmodel.fileinfothread")
FileInfoThread::FileInfoThread(QObject *parent)
: QThread(parent),
diff --git a/src/labs/folderlistmodel/qquickfolderlistmodel.cpp b/src/labs/folderlistmodel/qquickfolderlistmodel.cpp
index af6fd3b2ef..6b1767d7a6 100644
--- a/src/labs/folderlistmodel/qquickfolderlistmodel.cpp
+++ b/src/labs/folderlistmodel/qquickfolderlistmodel.cpp
@@ -11,7 +11,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcFolderListModel, "qt.labs.folderlistmodel")
+Q_STATIC_LOGGING_CATEGORY(lcFolderListModel, "qt.labs.folderlistmodel")
class QQuickFolderListModelPrivate
{
diff --git a/src/labs/models/CMakeLists.txt b/src/labs/models/CMakeLists.txt
index 6c6697a5a5..0ae2d7d16e 100644
--- a/src/labs/models/CMakeLists.txt
+++ b/src/labs/models/CMakeLists.txt
@@ -15,7 +15,6 @@ qt_internal_add_qml_module(LabsQmlModels
Qt::QmlPrivate
DEPENDENCIES
QtQml.Models/auto
- GENERATE_CPP_EXPORTS
)
qt_internal_extend_target(LabsQmlModels CONDITION QT_FEATURE_qml_table_model
diff --git a/src/labs/models/qqmltablemodel.cpp b/src/labs/models/qqmltablemodel.cpp
index 6b14eeaaef..adf187f225 100644
--- a/src/labs/models/qqmltablemodel.cpp
+++ b/src/labs/models/qqmltablemodel.cpp
@@ -9,7 +9,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcTableModel, "qt.qml.tablemodel")
+Q_STATIC_LOGGING_CATEGORY(lcTableModel, "qt.qml.tablemodel")
/*!
\qmltype TableModel
diff --git a/src/labs/platform/qquicklabsplatformdialog.cpp b/src/labs/platform/qquicklabsplatformdialog.cpp
index 1e38d2d782..6566dcefa0 100644
--- a/src/labs/platform/qquicklabsplatformdialog.cpp
+++ b/src/labs/platform/qquicklabsplatformdialog.cpp
@@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE
\sa accepted()
*/
-Q_LOGGING_CATEGORY(qtLabsPlatformDialogs, "qt.labs.platform.dialogs")
+Q_STATIC_LOGGING_CATEGORY(qtLabsPlatformDialogs, "qt.labs.platform.dialogs")
QQuickLabsPlatformDialog::QQuickLabsPlatformDialog(QPlatformTheme::DialogType type, QObject *parent)
: QObject(parent),
diff --git a/src/labs/platform/qquicklabsplatformmenu_p.h b/src/labs/platform/qquicklabsplatformmenu_p.h
index 21fe2a286f..130b3418d7 100644
--- a/src/labs/platform/qquicklabsplatformmenu_p.h
+++ b/src/labs/platform/qquicklabsplatformmenu_p.h
@@ -15,6 +15,7 @@
// We mean it.
//
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qobject.h>
#include <QtCore/qurl.h>
#include <QtGui/qfont.h>
@@ -27,6 +28,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(qtLabsPlatformMenus)
+
class QIcon;
class QWindow;
class QQuickItem;
diff --git a/src/labs/platform/qquicklabsplatformmenubar.cpp b/src/labs/platform/qquicklabsplatformmenubar.cpp
index 8c0b4fd042..54d3d76b45 100644
--- a/src/labs/platform/qquicklabsplatformmenubar.cpp
+++ b/src/labs/platform/qquicklabsplatformmenubar.cpp
@@ -71,8 +71,6 @@ QT_BEGIN_NAMESPACE
\sa Menu
*/
-Q_DECLARE_LOGGING_CATEGORY(qtLabsPlatformMenus)
-
QQuickLabsPlatformMenuBar::QQuickLabsPlatformMenuBar(QObject *parent)
: QObject(parent),
m_complete(false),
diff --git a/src/labs/platform/qquicklabsplatformsystemtrayicon.cpp b/src/labs/platform/qquicklabsplatformsystemtrayicon.cpp
index dee37a50f7..4bc46ce729 100644
--- a/src/labs/platform/qquicklabsplatformsystemtrayicon.cpp
+++ b/src/labs/platform/qquicklabsplatformsystemtrayicon.cpp
@@ -130,7 +130,7 @@ QT_BEGIN_NAMESPACE
\sa showMessage()
*/
-Q_LOGGING_CATEGORY(qtLabsPlatformTray, "qt.labs.platform.tray")
+Q_STATIC_LOGGING_CATEGORY(qtLabsPlatformTray, "qt.labs.platform.tray")
QQuickLabsPlatformSystemTrayIcon::QQuickLabsPlatformSystemTrayIcon(QObject *parent)
: QObject(parent),
diff --git a/src/labs/settings/CMakeLists.txt b/src/labs/settings/CMakeLists.txt
index d9d53fab24..6b14e97443 100644
--- a/src/labs/settings/CMakeLists.txt
+++ b/src/labs/settings/CMakeLists.txt
@@ -14,5 +14,4 @@ qt_internal_add_qml_module(LabsSettings
PUBLIC_LIBRARIES
Qt::Core
Qt::Qml
- GENERATE_CPP_EXPORTS
)
diff --git a/src/labs/settings/qqmlsettings.cpp b/src/labs/settings/qqmlsettings.cpp
index 19ebdaf3c2..e012ec408d 100644
--- a/src/labs/settings/qqmlsettings.cpp
+++ b/src/labs/settings/qqmlsettings.cpp
@@ -18,7 +18,7 @@ QT_BEGIN_NAMESPACE
\qmlmodule Qt.labs.settings 1.0
\title Qt Labs Settings QML Types
\ingroup qmlmodules
- \deprecated [6.5] Use \l [QML] {QtCore::}{Settings} from Qt QML Core instead.
+ \deprecated [6.5] Use \l [QML] {QtCore::}{Settings} from Qt Qml Core instead.
\brief Provides persistent platform-independent application settings.
To use this module, import the module with the following line:
@@ -33,7 +33,7 @@ QT_BEGIN_NAMESPACE
//! \instantiates QQmlSettings
\inqmlmodule Qt.labs.settings
\ingroup settings
- \deprecated [6.5] Use \l [QML] {QtCore::}{Settings} from Qt QML Core instead.
+ \deprecated [6.5] Use \l [QML] {QtCore::}{Settings} from Qt Qml Core instead.
\brief Provides persistent platform-independent application settings.
The Settings type provides persistent platform-independent application settings.
@@ -201,7 +201,7 @@ QT_BEGIN_NAMESPACE
\sa {QtCore::}{Settings}, QSettings
*/
-Q_LOGGING_CATEGORY(lcSettings, "qt.labs.settings")
+Q_STATIC_LOGGING_CATEGORY(lcSettings, "qt.labs.settings")
static const int settingsWriteDelay = 500;
diff --git a/src/labs/sharedimage/CMakeLists.txt b/src/labs/sharedimage/CMakeLists.txt
index 8cbe5b62cc..d551bdf5cb 100644
--- a/src/labs/sharedimage/CMakeLists.txt
+++ b/src/labs/sharedimage/CMakeLists.txt
@@ -19,7 +19,6 @@ qt_internal_add_qml_module(LabsSharedImage
Qt::CorePrivate
Qt::GuiPrivate
Qt::QuickPrivate
- GENERATE_CPP_EXPORTS
)
# We need to do additional initialization, so we have to provide our own
diff --git a/src/labs/wavefrontmesh/CMakeLists.txt b/src/labs/wavefrontmesh/CMakeLists.txt
index eb68fa2947..5b0bdde643 100644
--- a/src/labs/wavefrontmesh/CMakeLists.txt
+++ b/src/labs/wavefrontmesh/CMakeLists.txt
@@ -17,5 +17,4 @@ qt_internal_add_qml_module(LabsWavefrontMesh
Qt::CorePrivate
Qt::GuiPrivate
Qt::QuickPrivate
- GENERATE_CPP_EXPORTS
)
diff --git a/src/particles/CMakeLists.txt b/src/particles/CMakeLists.txt
index 9746349d81..7516f23b21 100644
--- a/src/particles/CMakeLists.txt
+++ b/src/particles/CMakeLists.txt
@@ -63,7 +63,6 @@ qt_internal_add_qml_module(QuickParticlesPrivate
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
- GENERATE_CPP_EXPORTS
)
# Resources:
diff --git a/src/plugins/qmllint/quick/CMakeLists.txt b/src/plugins/qmllint/quick/CMakeLists.txt
index 7064f19a7f..cf729cf3d7 100644
--- a/src/plugins/qmllint/quick/CMakeLists.txt
+++ b/src/plugins/qmllint/quick/CMakeLists.txt
@@ -7,6 +7,8 @@ qt_internal_add_plugin(QmlLintQuickPlugin
SOURCES
quicklintplugin.h
quicklintplugin.cpp
+ qquickliteralbindingcheck.cpp qquickliteralbindingcheck_p.h
+ qquickvaluetypefromstringcheck.cpp qquickvaluetypefromstringcheck_p.h
LIBRARIES
Qt::QmlCompilerPrivate
)
diff --git a/src/plugins/qmllint/quick/qquickliteralbindingcheck.cpp b/src/plugins/qmllint/quick/qquickliteralbindingcheck.cpp
new file mode 100644
index 0000000000..a39ea6d2c9
--- /dev/null
+++ b/src/plugins/qmllint/quick/qquickliteralbindingcheck.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qquickliteralbindingcheck_p.h"
+#include "qquickvaluetypefromstringcheck_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+QQmlJSStructuredTypeError QQuickLiteralBindingCheck::check(const QString &typeName,
+ const QString &value) const
+{
+ return QQuickValueTypeFromStringCheck::check(typeName, value);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/qmllint/quick/qquickliteralbindingcheck_p.h b/src/plugins/qmllint/quick/qquickliteralbindingcheck_p.h
new file mode 100644
index 0000000000..058b5f7f5c
--- /dev/null
+++ b/src/plugins/qmllint/quick/qquickliteralbindingcheck_p.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QQUICKLITERALBINDINGCHECK_H
+#define QQUICKLITERALBINDINGCHECK_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 <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+#include <private/qqmljsliteralbindingcheck_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlJSImportVisitor;
+class QQmlJSTypeResolver;
+
+class QQuickLiteralBindingCheck: public LiteralBindingCheckBase
+{
+public:
+ using LiteralBindingCheckBase::LiteralBindingCheckBase;
+
+ virtual QQmlJSStructuredTypeError check(const QString &typeName,
+ const QString &value) const override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKLITERALBINDINGCHECK_H
diff --git a/src/plugins/qmllint/quick/qquickvaluetypefromstringcheck.cpp b/src/plugins/qmllint/quick/qquickvaluetypefromstringcheck.cpp
new file mode 100644
index 0000000000..40f1d674f9
--- /dev/null
+++ b/src/plugins/qmllint/quick/qquickvaluetypefromstringcheck.cpp
@@ -0,0 +1,81 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qquickvaluetypefromstringcheck_p.h"
+
+#include <private/qqmlstringconverters_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+QQmlJSStructuredTypeError QQuickValueTypeFromStringCheck::check(const QString &typeName,
+ const QString &value)
+{
+ if (typeName == u"QVector2D") {
+ std::array<double, 2> parameters;
+ if (!QQmlStringConverters::isValidNumberString<2, u','>(value, &parameters))
+ return QQmlJSStructuredTypeError::withInvalidString();
+
+ const auto result = QQmlJSStructuredTypeError::fromSuggestedString(
+ u"({ x: %1, y: %2 })"_s.arg(parameters[0]).arg(parameters[1]));
+ return result;
+ } else if (typeName == u"QVector3D") {
+ std::array<double, 3> parameters;
+ if (!QQmlStringConverters::isValidNumberString<3, u',', u','>(value, &parameters))
+ return QQmlJSStructuredTypeError::withInvalidString();
+
+ const auto result = QQmlJSStructuredTypeError::fromSuggestedString(
+ u"({ x: %1, y: %2, z: %3 })"_s.arg(parameters[0])
+ .arg(parameters[1])
+ .arg(parameters[2]));
+ return result;
+ } else if (typeName == u"QVector4D") {
+ std::array<double, 4> parameters;
+ if (!QQmlStringConverters::isValidNumberString<4, u',', u',', u','>(value, &parameters))
+ return QQmlJSStructuredTypeError::withInvalidString();
+
+ const auto result = QQmlJSStructuredTypeError::fromSuggestedString(
+ u"({ x: %1, y: %2, z: %3, w: %4 })"_s.arg(parameters[0])
+ .arg(parameters[1])
+ .arg(parameters[2])
+ .arg(parameters[3]));
+ return result;
+ } else if (typeName == u"QQuaternion") {
+ std::array<double, 4> parameters;
+ if (!QQmlStringConverters::isValidNumberString<4, u',', u',', u','>(value, &parameters))
+ return QQmlJSStructuredTypeError::withInvalidString();
+
+ const auto result = QQmlJSStructuredTypeError::fromSuggestedString(
+ u"({ scalar: %1, x: %2, y: %3, z: %4 })"_s.arg(parameters[0])
+ .arg(parameters[1])
+ .arg(parameters[2])
+ .arg(parameters[3]));
+ return result;
+ } else if (typeName == u"QMatrix4x4") {
+ std::array<double, 16> parameters;
+ if (!QQmlStringConverters::isValidNumberString<16, u',', u',', u',', u',', u',', u',', u',',
+ u',', u',', u',', u',', u',', u',', u',',
+ u','>(value, &parameters)) {
+ return QQmlJSStructuredTypeError::withInvalidString();
+ }
+
+ QString construction = u"({ "_s;
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ construction.append(
+ u"m%1%2: %3"_s.arg(i + 1).arg(j + 1).arg(parameters[i * 4 + j]));
+ if (!(i == 3 && j == 3))
+ construction.append(u", "_s);
+ }
+ }
+ construction.append(u" })"_s);
+
+ const auto result = QQmlJSStructuredTypeError::fromSuggestedString(construction);
+ return result;
+ }
+
+ return QQmlJSStructuredTypeError::withValidString();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/qmllint/quick/qquickvaluetypefromstringcheck_p.h b/src/plugins/qmllint/quick/qquickvaluetypefromstringcheck_p.h
new file mode 100644
index 0000000000..79575e80cf
--- /dev/null
+++ b/src/plugins/qmllint/quick/qquickvaluetypefromstringcheck_p.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QQUICKVALUETYPEFROMSTRINGCHECK_H
+#define QQUICKVALUETYPEFROMSTRINGCHECK_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 <QtCore/qglobal.h>
+#include <QtCore/qstring.h>
+#include <private/qqmljsvaluetypefromstringcheck_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickValueTypeFromStringCheck
+{
+public:
+ static QQmlJSStructuredTypeError check(const QString &typeName, const QString &value);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKVALUETYPEFROMSTRINGCHECK_H
diff --git a/src/plugins/qmllint/quick/quicklintplugin.cpp b/src/plugins/qmllint/quick/quicklintplugin.cpp
index 15b947a10c..9a61e7a429 100644
--- a/src/plugins/qmllint/quick/quicklintplugin.cpp
+++ b/src/plugins/qmllint/quick/quicklintplugin.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "quicklintplugin.h"
+#include "qquickliteralbindingcheck_p.h"
QT_BEGIN_NAMESPACE
@@ -610,6 +611,8 @@ void QmlLintQuickPlugin::registerPasses(QQmlSA::PassManager *manager,
if (hasQuick) {
manager->registerElementPass(std::make_unique<AnchorsValidatorPass>(manager));
manager->registerElementPass(std::make_unique<PropertyChangesValidatorPass>(manager));
+ manager->registerPropertyPass(std::make_unique<QQuickLiteralBindingCheck>(manager),
+ QAnyStringView(), QAnyStringView());
auto forbiddenChildProperty =
std::make_unique<ForbiddenChildrenPropertyValidatorPass>(manager);
@@ -675,7 +678,7 @@ void QmlLintQuickPlugin::registerPasses(QQmlSA::PassManager *manager,
{ { "columnWidthProvider", { "", "function" } },
{ "rowHeightProvider", { "", "function" } } });
addAttachedWarning({ "QtQuick", "Accessible" }, { { "QtQuick", "Item" } },
- "Accessible must be attached to an Item");
+ "Accessible must be attached to an Item or an Action");
addAttachedWarning({ "QtQuick", "LayoutMirroring" },
{ { "QtQuick", "Item" }, { "QtQuick", "Window" } },
"LayoutDirection attached property only works with Items and Windows");
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
index 3bd37878a8..f678eb905b 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
@@ -761,7 +761,8 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth
QV4::Scope scope(v4);
int lineNumber = 0;
- QV4::ScopedFunctionObject oldMethod(scope, vmeMetaObject->vmeMethod(prop->coreIndex()));
+ QV4::Scoped<QV4::JavaScriptFunctionObject> oldMethod(
+ scope, vmeMetaObject->vmeMethod(prop->coreIndex()));
if (oldMethod && oldMethod->d()->function)
lineNumber = oldMethod->d()->function->compiledFunction->location.line();
diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt
index cbcdc2f8f9..5ed8abf904 100644
--- a/src/qml/CMakeLists.txt
+++ b/src/qml/CMakeLists.txt
@@ -31,65 +31,13 @@ if(ANDROID)
"${INSTALL_CMAKE_NAMESPACE}AndroidQmlMacros.cmake")
endif()
-set_source_files_properties(
- qml/qqmlcomponent.h qml/qqmlcomponent.cpp qml/qqmlcomponent_p.h
- qml/qqmlcomponentattached_p.h
- qml/qqmlscriptstring.h qml/qqmlscriptstring_p.h qml/qqmlscriptstring.cpp
- PROPERTIES
- SKIP_AUTOMOC TRUE
-)
-
-set(extra_manual_moc_deps "")
-if(QT_FEATURE_qml_network)
- list(APPEND extra_manual_moc_deps Qt6::Network)
-endif()
-# We want QQmlComponent, QQmlComponentAttached, and QQmlScriptString to be available as metatypes in
-# the builtins, but without depending on QtQml and without duplicating the metaobjects.
-qt_manual_moc(extra_builtins_moc_files
- OUTPUT_MOC_JSON_FILES extra_builtins_json_list
- qml/qqmlcomponent.h
- qml/qqmlcomponentattached_p.h
- qml/qqmlscriptstring.h
- TARGETS Qt6::Qml Qt6::Core ${extra_manual_moc_deps}
-)
-
-# The moc files are included directly by qqmlcomponent.cpp and qqmlscriptstring.cpp
-set_source_files_properties(${extra_builtins_moc_files} PROPERTIES HEADER_FILE_ONLY ON)
-
-qt_internal_add_module(QmlBuiltins
- STATIC
- NO_GENERATE_METATYPES # we do that manually below
- SOURCES
- qqmlbuiltins_p.h
-)
-
-add_custom_target(ExtraBuiltinsJson DEPENDS ${extra_builtins_json_list})
-add_custom_target(ExtraBuiltinsMocs DEPENDS ${extra_builtins_moc_files})
-
-target_link_libraries(QmlBuiltins PRIVATE Qt::Core Qt::QmlIntegration)
-
-# We generally need to copy the files into the build directory,
-# so that they are located together with the QML modules
-qt_path_join(qml_build_dir "${QT_BUILD_DIR}" "${INSTALL_QMLDIR}")
-
-# Simulate conditions that qt6_add_qml_module() would normally set up for us
-set_target_properties(QmlBuiltins PROPERTIES
- QT_QML_MODULE_VERSION 1.0
- QT_QML_MODULE_URI QML
- QT_QML_MODULE_TYPEINFO builtins.qmltypes
- QT_QML_MODULE_OUTPUT_DIRECTORY ${qml_build_dir}
-)
-
qt_internal_add_qml_module(Qml
- URI "QtQml.Base"
- VERSION "${PROJECT_VERSION}"
+ URI "QML"
+ VERSION "1.0"
DESIGNER_SUPPORTED
__QT_INTERNAL_SYSTEM_MODULE
- PLUGIN_TARGET qmlplugin
- CLASS_NAME QtQmlPlugin
PLUGIN_TYPES qmltooling
- IMPORTS
- QML/1.0
+ NO_PLUGIN
SOURCES
../3rdparty/masm/assembler/ARM64Assembler.h
../3rdparty/masm/assembler/ARMv7Assembler.cpp ../3rdparty/masm/assembler/ARMv7Assembler.h
@@ -173,13 +121,13 @@ qt_internal_add_qml_module(Qml
common/qqmljsfixedpoolarray_p.h
common/qqmljsmemorypool_p.h
common/qqmljssourcelocation_p.h
+ common/qqmlsignalnames_p.h common/qqmlsignalnames.cpp
+ common/qqmltranslation.cpp common/qqmltranslation_p.h
common/qv4alloca_p.h
common/qv4calldata_p.h
common/qv4compileddata.cpp common/qv4compileddata_p.h
common/qv4staticvalue_p.h
common/qv4stringtoarrayindex_p.h
- common/qqmltranslation.cpp common/qqmltranslation_p.h
- common/qqmlsignalnames_p.h common/qqmlsignalnames.cpp
compat/removed_api.cpp
compiler/qqmlirbuilder.cpp compiler/qqmlirbuilder_p.h
compiler/qv4bytecodegenerator.cpp compiler/qv4bytecodegenerator_p.h
@@ -258,6 +206,7 @@ qt_internal_add_qml_module(Qml
jsruntime/qv4qmetaobjectwrapper.cpp jsruntime/qv4qmetaobjectwrapper_p.h
jsruntime/qv4qmlcontext.cpp jsruntime/qv4qmlcontext_p.h
jsruntime/qv4qobjectwrapper.cpp jsruntime/qv4qobjectwrapper_p.h
+ jsruntime/qv4referenceobject.cpp jsruntime/qv4referenceobject_p.h
jsruntime/qv4reflect.cpp jsruntime/qv4reflect_p.h
jsruntime/qv4regexp.cpp jsruntime/qv4regexp_p.h
jsruntime/qv4regexpobject.cpp jsruntime/qv4regexpobject_p.h
@@ -267,6 +216,7 @@ qt_internal_add_qml_module(Qml
jsruntime/qv4runtimecodegen.cpp jsruntime/qv4runtimecodegen_p.h
jsruntime/qv4scopedvalue_p.h
jsruntime/qv4script.cpp jsruntime/qv4script_p.h
+ jsruntime/qv4sequenceobject.cpp jsruntime/qv4sequenceobject_p.h
jsruntime/qv4setiterator.cpp jsruntime/qv4setiterator_p.h
jsruntime/qv4setobject.cpp jsruntime/qv4setobject_p.h
jsruntime/qv4sparsearray.cpp jsruntime/qv4sparsearray_p.h
@@ -281,9 +231,7 @@ qt_internal_add_qml_module(Qml
jsruntime/qv4value.cpp jsruntime/qv4value_p.h
jsruntime/qv4variantobject.cpp jsruntime/qv4variantobject_p.h
jsruntime/qv4vme_moth.cpp jsruntime/qv4vme_moth_p.h
- jsruntime/qv4sequenceobject.cpp jsruntime/qv4sequenceobject_p.h
jsruntime/qv4vtable_p.h
- jsruntime/qv4referenceobject.cpp jsruntime/qv4referenceobject_p.h
memory/qv4heap_p.h
memory/qv4mm.cpp memory/qv4mm_p.h
memory/qv4mmdefs_p.h
@@ -296,10 +244,10 @@ qt_internal_add_qml_module(Qml
parser/qqmljsglobal_p.h
parser/qqmljskeywords_p.h
parser/qqmljslexer.cpp parser/qqmljslexer_p.h
+ qml/ftw/qbipointer_p.h
qml/ftw/qdoubleendedlist_p.h
qml/ftw/qfieldlist_p.h
qml/ftw/qfinitestack_p.h
- qml/ftw/qbipointer_p.h
qml/ftw/qhashedstring.cpp qml/ftw/qhashedstring_p.h
qml/ftw/qintrusivelist.cpp qml/ftw/qintrusivelist_p.h
qml/ftw/qlazilyallocated_p.h
@@ -312,10 +260,10 @@ qt_internal_add_qml_module(Qml
qml/ftw/qrecursionwatcher_p.h
qml/ftw/qrecyclepool_p.h
qml/ftw/qstringhash_p.h
- qml/qqmlregistration.h
qml/qqml.cpp qml/qqml.h
qml/qqmlabstractbinding.cpp qml/qqmlabstractbinding_p.h
qml/qqmlabstracturlinterceptor.cpp qml/qqmlabstracturlinterceptor.h
+ qml/qqmlanybinding_p.h
qml/qqmlapplicationengine.cpp qml/qqmlapplicationengine.h qml/qqmlapplicationengine_p.h
qml/qqmlbinding.cpp qml/qqmlbinding_p.h
qml/qqmlboundsignal.cpp qml/qqmlboundsignal_p.h
@@ -339,6 +287,7 @@ qt_internal_add_qml_module(Qml
qml/qqmlextensionplugin.cpp qml/qqmlextensionplugin.h qml/qqmlextensionplugin_p.h
qml/qqmlfile.cpp qml/qqmlfile.h
qml/qqmlfileselector.cpp qml/qqmlfileselector.h qml/qqmlfileselector_p.h
+ qml/qqmlfinalizer.cpp qml/qqmlfinalizer_p.h
qml/qqmlglobal.cpp qml/qqmlglobal_p.h
qml/qqmlguard_p.h
qml/qqmlguardedcontextdata_p.h
@@ -349,8 +298,7 @@ qt_internal_add_qml_module(Qml
qml/qqmljavascriptexpression.cpp qml/qqmljavascriptexpression_p.h
qml/qqmllist.cpp qml/qqmllist.h qml/qqmllist_p.h
qml/qqmllistwrapper.cpp qml/qqmllistwrapper_p.h
- qml/qqmlloggingcategory.cpp qml/qqmlloggingcategory_p.h
- qml/qqmlmetamoduleregistration.cpp
+ qml/qqmlloggingcategorybase_p.h
qml/qqmlmetaobject.cpp qml/qqmlmetaobject_p.h
qml/qqmlmetatype.cpp qml/qqmlmetatype_p.h
qml/qqmlmetatypedata.cpp qml/qqmlmetatypedata_p.h
@@ -366,7 +314,6 @@ qt_internal_add_qml_module(Qml
qml/qqmlprivate.h
qml/qqmlproperty.cpp qml/qqmlproperty.h qml/qqmlproperty_p.h
qml/qqmlpropertybinding.cpp qml/qqmlpropertybinding_p.h
- qml/qqmlanybinding_p.h
qml/qqmlpropertycache.cpp qml/qqmlpropertycache_p.h
qml/qqmlpropertycachecreator.cpp qml/qqmlpropertycachecreator_p.h
qml/qqmlpropertycachemethodarguments_p.h
@@ -377,9 +324,9 @@ qt_internal_add_qml_module(Qml
qml/qqmlpropertytopropertybinding.cpp qml/qqmlpropertytopropertybinding_p.h
qml/qqmlpropertyvalidator.cpp qml/qqmlpropertyvalidator_p.h
qml/qqmlpropertyvalueinterceptor.cpp qml/qqmlpropertyvalueinterceptor_p.h
- qml/qqmlfinalizer.cpp qml/qqmlfinalizer_p.h
qml/qqmlpropertyvaluesource.cpp qml/qqmlpropertyvaluesource.h
qml/qqmlproxymetaobject.cpp qml/qqmlproxymetaobject_p.h
+ qml/qqmlregistration.h
qml/qqmlscriptblob.cpp qml/qqmlscriptblob_p.h
qml/qqmlscriptdata.cpp qml/qqmlscriptdata_p.h
qml/qqmlscriptstring.cpp qml/qqmlscriptstring.h qml/qqmlscriptstring_p.h
@@ -403,10 +350,9 @@ qt_internal_add_qml_module(Qml
qml/qqmlvmemetaobject.cpp qml/qqmlvmemetaobject_p.h
qmldirparser/qqmldirparser.cpp qmldirparser/qqmldirparser_p.h
qmldirparser/qqmlimportresolver.cpp qmldirparser/qqmlimportresolver_p.h
+ qqmlbuiltins_p.h
qtqmlcompilerglobal.h qtqmlcompilerglobal_p.h
qtqmlglobal.h qtqmlglobal_p.h
- types/qqmlbind.cpp types/qqmlbind_p.h
- types/qqmlconnections.cpp types/qqmlconnections_p.h
util/qqmlpropertymap.cpp util/qqmlpropertymap.h
qmltc/qqmltcobjectcreationhelper_p.h
@@ -440,7 +386,6 @@ qt_internal_add_qml_module(Qml
jsruntime/qv4module.cpp # QV4::Compiler::Module vs. QV4::Module
jsruntime/qv4vme_moth.cpp # 'MOTH_BEGIN_INSTR' macro redefined (from qv4instr_moth.cpp)
qml/qqmltypecompiler.cpp # 'COMPILE_EXCEPTION' macro redefined (from qqmlirbuilder.cpp)
- qml/qqmlmetamoduleregistration.cpp # declares 'registration' clashing with qml_* files
DEFINES
BUILDING_QT__
ENABLE_ASSEMBLER_WX_EXCLUSIVE=1
@@ -486,12 +431,11 @@ qt_internal_add_qml_module(Qml
PUBLIC_LIBRARIES
Qt::Core
Qt::QmlIntegration
- Qt::QmlBuiltins
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
- Qt::QmlBuiltinsPrivate
EXTRA_CMAKE_FILES
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}qmldirTemplate.cmake.in"
+ "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}qt.conf.in"
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlPluginTemplate.cpp.in"
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlFindQmlscInternal.cmake"
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlDeploySupport.cmake"
@@ -501,66 +445,47 @@ qt_internal_add_qml_module(Qml
EXTRA_CMAKE_INCLUDES
"${INSTALL_CMAKE_NAMESPACE}QmlFindQmlscInternal.cmake"
${extra_cmake_includes}
- GENERATE_CPP_EXPORTS
POLICIES
QTP0001
QTP0004
+ QTP0005
)
_qt_internal_add_qml_deploy_info_finalizer(Qml)
-target_include_directories(QmlBuiltins PRIVATE
- $<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::QmlPrivate,INTERFACE_INCLUDE_DIRECTORIES>
-)
-
-set(builtins_typeregistration_args
- MANUAL_MOC_JSON_FILES ${extra_builtins_json_list}
- REGISTRATIONS_TARGET Qml
-)
-
-get_target_property(qt_namespace ${QT_CMAKE_EXPORT_NAMESPACE}::Core _qt_namespace)
-if(qt_namespace)
- list(APPEND builtins_typeregistration_args NAMESPACE ${qt_namespace})
-endif()
-
-_qt_internal_qml_type_registration(QmlBuiltins ${builtins_typeregistration_args})
-add_dependencies(QmlBuiltins ExtraBuiltinsJson)
+qt_path_join(qml_root_dir "${QT_BUILD_DIR}" "${INSTALL_QMLDIR}")
+get_target_property(qml_build_dir Qml QT_QML_MODULE_OUTPUT_DIRECTORY)
_qt_internal_get_tool_wrapper_script_path(tool_wrapper)
add_custom_command(
OUTPUT
- "${qml_build_dir}/jsroot.qmltypes"
+ "${qml_root_dir}/jsroot.qmltypes"
DEPENDS
${QT_CMAKE_EXPORT_NAMESPACE}::qmltyperegistrar
COMMAND
${tool_wrapper}
$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qmltyperegistrar>
- --jsroot --generate-qmltypes "${qml_build_dir}/jsroot.qmltypes"
+ --jsroot --generate-qmltypes "${qml_root_dir}/jsroot.qmltypes"
COMMENT "Generating jsroot.qmltypes"
VERBATIM
)
-get_target_property(builtins_metatypes_file "QmlBuiltins" INTERFACE_QT_META_TYPES_BUILD_FILE)
-
-_qt_internal_get_metatypes_install_dir(
- ""
- "${INSTALL_ARCHDATADIR}"
- metatypes_install_dir
-)
-
-_qt_internal_assign_install_metatypes_files_and_properties(
- QmlBuiltins
- INSTALL_DIR "${metatypes_install_dir}"
-)
-
-qt_install(
- FILES "${builtins_metatypes_file}"
- DESTINATION "${metatypes_install_dir}"
+add_custom_command(
+ OUTPUT
+ "${qml_root_dir}/builtins.qmltypes"
+ DEPENDS
+ "${qml_build_dir}/plugins.qmltypes"
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different
+ "${qml_build_dir}/plugins.qmltypes"
+ "${qml_root_dir}/builtins.qmltypes"
+ COMMENT "Copying builtins.qmltypes"
+ VERBATIM
)
set(builtins_output_files "")
-list(APPEND builtins_output_files "${qml_build_dir}/builtins.qmltypes")
-list(APPEND builtins_output_files "${qml_build_dir}/jsroot.qmltypes")
+list(APPEND builtins_output_files "${qml_root_dir}/builtins.qmltypes")
+list(APPEND builtins_output_files "${qml_root_dir}/jsroot.qmltypes")
add_custom_target(BuiltinsOutput DEPENDS ${builtins_output_files})
@@ -569,9 +494,6 @@ qt_install(
DESTINATION "${INSTALL_QMLDIR}"
)
-add_dependencies(Qml ExtraBuiltinsMocs)
-add_dependencies(Qml BuiltinsOutput)
-
qt_update_ignore_pch_source(Qml "compat/removed_api.cpp")
set_source_files_properties(compat/removed_api.cpp
@@ -583,30 +505,23 @@ qt_internal_add_qml_module(QmlMeta
URI "QtQml"
VERSION "${PROJECT_VERSION}"
DESIGNER_SUPPORTED
- CLASS_NAME QtQmlMetaPlugin
- PLUGIN_TARGET QmlMeta
-
- # Prevent type registration
- NO_GENERATE_QMLTYPES
-
+ __QT_INTERNAL_SYSTEM_MODULE
+ PLUGIN_TARGET qmlplugin
+ CLASS_NAME QtQmlPlugin
PAST_MAJOR_VERSIONS 2
IMPORTS
- QtQml.Base/auto
+ QML/1.0
${module_dynamic_qml_imports}
+ SOURCES
+ types/qqmlbind.cpp types/qqmlbind_p.h
+ types/qqmlconnections.cpp types/qqmlconnections_p.h
+ types/qqmlloggingcategory.cpp types/qqmlloggingcategory_p.h
+ LIBRARIES
+ Qml
+ QmlModels
)
-# Add the QtQml qmldir to libQtQml, too.
-# Since we also provide the (bare bones) type registration in libQtQml,
-# this makes the complete module reside in libQtQml. There is no need to
-# load the QmlMeta plugin, then.
-# Se still provide the plugin so that static linking works.
-get_target_property(qtqml_out_dir QmlMeta QT_QML_MODULE_OUTPUT_DIRECTORY)
-qt_internal_add_resource(Qml "qmlMetaQmldir"
- PREFIX
- "/qt-project.org/imports/QtQml"
- FILES
- ${qtqml_out_dir}/qmldir
-)
+add_dependencies(QmlMeta BuiltinsOutput)
# Linking to the static qml plugin should also automatically link to the worker script
# static plugin otherwise you get errors like
@@ -614,14 +529,15 @@ qt_internal_add_resource(Qml "qmlMetaQmldir"
# import QtQuick 2.0
# ^
if(QT_FEATURE_qml_worker_script)
+ target_link_libraries(QmlMeta PRIVATE QmlWorkerScript)
_qt_internal_add_qml_static_plugin_dependency(qmlplugin workerscriptplugin)
endif()
-# Same for the QmlMeta qml plugin, otherwise you get
+# Same for the QmlModels qml plugin, otherwise you get
# module "QtQuick" version 6.6 cannot be imported because:
-# module "QtQml" plugin "qmlmetaplugin" not found
+# module "QtQml.Models" plugin "modelsplugin" not found
# import QtQuick
# ^
-_qt_internal_add_qml_static_plugin_dependency(qmlplugin QmlMeta)
+_qt_internal_add_qml_static_plugin_dependency(qmlplugin modelsplugin)
# special case begin remove the block, handled manually
# QLALR Grammars:
@@ -714,6 +630,12 @@ qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_animation
animations/qparallelanimationgroupjob.cpp animations/qparallelanimationgroupjob_p.h
animations/qpauseanimationjob.cpp animations/qpauseanimationjob_p.h
animations/qsequentialanimationgroupjob.cpp animations/qsequentialanimationgroupjob_p.h
+ INCLUDE_DIRECTORIES
+ animations
+)
+
+qt_internal_extend_target(QmlMeta CONDITION QT_FEATURE_qml_animation
+ SOURCES
types/qqmltimer.cpp types/qqmltimer_p.h
INCLUDE_DIRECTORIES
animations
@@ -778,6 +700,11 @@ qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_locale
qml/qqmllocale.cpp qml/qqmllocale_p.h
)
+qt_internal_extend_target(QmlMeta CONDITION QT_FEATURE_qml_locale
+ SOURCES
+ types/qqmllocaleenums_p.h
+)
+
qt_internal_extend_target(Qml CONDITION ANDROID
DEFINES
LIBS_SUFFIX="_${ANDROID_ABI}.so" # special case
@@ -875,10 +802,8 @@ endif()
# "unknown IID" issue when moc processes plugin sources, because of missing header aliases.
# Qml_sync_headers target is created later by the finalizer in the directory scope so we add this
# dependency manually instead of relying on qt_internal_add_qml_module logic. Same is applicable
-# for the QmlMeta and the QmlBuiltins target.
+# for the QmlMeta target.
set_property(TARGET qmlplugin APPEND PROPERTY AUTOGEN_TARGET_DEPENDS
Qml_sync_headers)
set_property(TARGET QmlMeta APPEND PROPERTY AUTOGEN_TARGET_DEPENDS
Qml_sync_headers)
-set_property(TARGET QmlBuiltins APPEND PROPERTY AUTOGEN_TARGET_DEPENDS
- Qml_sync_headers)
diff --git a/src/qml/Qt6AndroidQmlMacros.cmake b/src/qml/Qt6AndroidQmlMacros.cmake
index 5f6f01fd76..0a17665d5b 100644
--- a/src/qml/Qt6AndroidQmlMacros.cmake
+++ b/src/qml/Qt6AndroidQmlMacros.cmake
@@ -135,5 +135,13 @@ function(_qt_internal_generate_android_qml_deployment_settings out_var target)
_qt_internal_add_tool_to_android_deployment_settings(${out_var} qmlimportscanner
"qml-importscanner-binary" ${target})
+ # Add qml-dom-binary binary path
+ _qt_internal_add_tool_to_android_deployment_settings(${out_var} qmldom "qml-dom-binary"
+ "${target}")
+
+
+ _qt_internal_add_android_deployment_list_property(${out_var} "qml-files-for-code-generator"
+ ${target} "_qt_qml_files_for_java_generator")
+
set(${out_var} "${${out_var}}" PARENT_SCOPE)
endfunction()
diff --git a/src/qml/Qt6QmlDeploySupport.cmake b/src/qml/Qt6QmlDeploySupport.cmake
index a230e71409..1b43059cc2 100644
--- a/src/qml/Qt6QmlDeploySupport.cmake
+++ b/src/qml/Qt6QmlDeploySupport.cmake
@@ -159,6 +159,11 @@ function(_qt_internal_deploy_qml_imports_for_target)
# file names, so account for those. There should never be plugin
# libraries for more than one QML module in the directory, so we
# shouldn't need to worry about matching plugins we don't want.
+ #
+ # install_qmldir and install_plugin do not contain $ENV{DESTDIR},
+ # whereas dest_qmldir and dest_plugin do.
+ # The install_ variants are used in file(INSTALL) to avoid double DESTDIR in paths.
+ # Other code should reference the dest_ variants instead.
set(relative_qmldir "${arg_QML_DIR}/${entry_RELATIVEPATH}")
if("${CMAKE_INSTALL_PREFIX}" STREQUAL "")
set(install_qmldir "./${relative_qmldir}")
@@ -180,6 +185,12 @@ function(_qt_internal_deploy_qml_imports_for_target)
file(INSTALL "${entry_PATH}/qmldir" DESTINATION "${install_qmldir}")
+ if(DEFINED __QT_DEPLOY_TARGET_${entry_LINKTARGET}_FILE AND
+ __QT_DEPLOY_TARGET_${entry_LINKTARGET}_TYPE STREQUAL "STATIC_LIBRARY")
+ # If the QML plugin is built statically, skip further deployment.
+ continue()
+ endif()
+
if(__QT_DEPLOY_POST_BUILD)
# We are being invoked as a post-build step. The plugin might
# not exist yet, so we can't even glob for it, let alone copy
diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake
index a64e2eea6b..d0ee634b8f 100644
--- a/src/qml/Qt6QmlMacros.cmake
+++ b/src/qml/Qt6QmlMacros.cmake
@@ -13,6 +13,129 @@ set(__qt_qml_macros_module_base_dir "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "
include(GNUInstallDirs)
_qt_internal_add_deploy_support("${CMAKE_CURRENT_LIST_DIR}/Qt6QmlDeploySupport.cmake")
+# This function is used to parse DEPENDENCY and IMPORT entries passed to qt_add_qml_module
+# It takes the entry as a mandatory argument, and then sets the following
+# user provided properties in the callers scope
+# OUTPUT_URI <property>: the URI of the module; mandatory argument
+# OUTPUT_VERSION <property>: the requested version of the module; will potentially be empty; mandatory
+# OUTPUT_MODULE_LOCATION <property>: the folder in which the module is located; optional; can be used to extract potential import path
+# OUTPUT_MODULE_TARGET <property>: the target corresponding to the module
+
+function(_qt_internal_parse_qml_module_dependency dependency was_marked_as_target)
+ set(args_option "")
+ set(args_single OUTPUT_URI OUTPUT_VERSION OUTPUT_MODULE_LOCATION OUTPUT_MODULE_TARGET)
+ set(args_multi QML_FILES IMPORT_PATHS)
+
+ cmake_parse_arguments(PARSE_ARGV 2 arg
+ "${args_option}" "${args_single}" "${args_multi}"
+ )
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown/unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ if(NOT arg_OUTPUT_URI)
+ message(FATAL_ERROR "Missing output URI variable")
+ endif()
+ if(NOT arg_OUTPUT_VERSION)
+ message(FATAL_ERROR "Missing output version variable")
+ endif()
+
+ set(dep_version "")
+ set(dep_target_or_uri "")
+ string(FIND "${dependency}" "/" slash_position REVERSE)
+ if(slash_position EQUAL -1)
+ set(dep_target_or_uri "${dependency}")
+ else()
+ string(SUBSTRING "${dependency}" 0 ${slash_position} dep_module)
+ math(EXPR slash_position "${slash_position} + 1")
+ string(SUBSTRING "${dependency}" ${slash_position} -1 dep_version)
+ if(NOT dep_version MATCHES "^([0-9]+(\\.[0-9]+)?|auto)$")
+ message(FATAL_ERROR
+ "Invalid module dependency version number. "
+ "Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'."
+ )
+ endif()
+ set(dep_target_or_uri "${dep_module}")
+ endif()
+ if("${was_marked_as_target}" AND NOT TARGET ${dep_target_or_uri})
+ message(FATAL_ERROR "Argument ${dep_target_or_uri} is not a target!")
+ endif()
+ if("${was_marked_as_target}")
+ qt6_query_qml_module(${dep_target_or_uri}
+ URI dependency_uri
+ QMLDIR qmldir_location
+ )
+ set(dep_module ${dependency_uri})
+ else()
+ set(dep_module "${dep_target_or_uri}")
+ endif()
+ set(${arg_OUTPUT_URI} ${dep_module} PARENT_SCOPE)
+ set(${arg_OUTPUT_VERSION} ${dep_version} PARENT_SCOPE)
+ if(arg_OUTPUT_MODULE_LOCATION)
+ if(was_marked_as_target)
+ if(NOT qmldir_location)
+ message(FATAL_ERROR "module has no qmldir! Given target was ${dep_target_or_uri}")
+ endif()
+ set(module_location "${qmldir_location}")
+ string(REGEX MATCHALL "\\." matches "${dependency_uri}")
+ list(LENGTH matches go_up_count)
+ # inclusive, which is what we want here: go up once for the qmldir,
+ # and then once per separated component
+ foreach(i RANGE ${go_up_count})
+ get_filename_component(module_location "${module_location}" DIRECTORY)
+ endforeach()
+ set(${arg_OUTPUT_MODULE_LOCATION} "${module_location}" PARENT_SCOPE)
+ else()
+ set(${arg_OUTPUT_MODULE_LOCATION} "NOTFOUND" PARENT_SCOPE)
+ endif()
+ endif()
+ if (arg_OUTPUT_MODULE_TARGET AND was_marked_as_target)
+ set(${arg_OUTPUT_MODULE_TARGET} "${dep_target_or_uri}" PARENT_SCOPE)
+ else()
+ set(${arg_OUTPUT_MODULE_TARGET} "" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_qt_internal_write_deferred_builddir_qtconf folder)
+ set(qt_all_qml_output_dirs "")
+ get_directory_property(targets
+ DIRECTORY "${folder}"
+ QT_QML_TARGETS_FOR_DEFERRED_QTCONF_WRITEOUT
+ )
+ set(qtconf_file "${folder}/qt.conf")
+ foreach(target IN LISTS ${targets})
+ get_target_property(dependency_targets "${target}" QT_QML_DEPENDENT_QML_MODULE_TARGETS)
+ if(NOT dependency_targets)
+ continue()
+ endif()
+ foreach(dep_target ${dependency_targets})
+ qt6_query_qml_module(${dep_target}
+ QMLDIR qmldir_location
+ )
+ get_filename_component(module_location "${qmldir_location}" DIRECTORY)
+ get_filename_component(module_import_path "${module_location}" DIRECTORY)
+ list(APPEND qt_all_qml_output_dirs ${module_import_path})
+ endforeach()
+ endforeach()
+ if (NOT qt_all_qml_output_dirs)
+ return()
+ endif()
+
+ list(REMOVE_DUPLICATES qt_all_qml_output_dirs)
+ # lists are just strings containing semicolons;
+ # we replace them with "," to get the right format for qtconf.
+ # However, we need to add quotes to deal with whitespace
+ list(TRANSFORM qt_all_qml_output_dirs APPEND "\"")
+ list(TRANSFORM qt_all_qml_output_dirs PREPEND "\"")
+ list(JOIN qt_all_qml_output_dirs "," qt_all_qml_output_dirs)
+
+ configure_file(
+ ${__qt_qml_macros_module_base_dir}/Qt6qtconf.in ${qtconf_file}
+ @ONLY
+ )
+endfunction()
+
+
function(qt6_add_qml_module target)
set(args_option
STATIC
@@ -391,53 +514,93 @@ function(qt6_add_qml_module target)
set(arg_TYPEINFO ${target}.qmltypes)
endif()
+ set(all_qml_import_paths "${arg_IMPORT_PATH}")
+ set(all_dependency_targets)
+
+ set(original_no_show_policy_value "${QT_NO_SHOW_OLD_POLICY_WARNINGS}")
+ # silent by default, we only warn if someone uses TARGET as a URI
+ set(QT_NO_SHOW_OLD_POLICY_WARNINGS TRUE)
+ __qt_internal_setup_policy(QTP0005 "6.8.0"
+ "" # intentionally empty as we silence the warning anyway
+ )
+ qt6_policy(GET QTP0005 allow_targets_for_dependencies_policy)
+ set(QT_NO_SHOW_OLD_POLICY_WARNINGS "${original_no_show_policy_value}")
+ string(COMPARE EQUAL "${allow_targets_for_dependencies_policy}" "NEW" target_is_keyword)
+
+
+ set(target_keyword_was_set FALSE)
foreach(import_set IN ITEMS IMPORTS OPTIONAL_IMPORTS DEFAULT_IMPORTS)
foreach(import IN LISTS arg_${import_set})
- string(FIND ${import} "/" slash_position REVERSE)
- if (slash_position EQUAL -1)
+ if (import STREQUAL "TARGET")
+ if (target_is_keyword)
+ set(target_keyword_was_set TRUE)
+ continue()
+ else()
+ message(AUTHOR_WARNING "TARGET is treated as a URI because QTP0005 is set to OLD. This is deprecated behavior. Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0005.html for policy details.")
+ set(target_keyword_was_set FALSE)
+ endif()
+ endif()
+ _qt_internal_parse_qml_module_dependency(${import} ${target_keyword_was_set}
+ OUTPUT_URI import_uri
+ OUTPUT_VERSION import_version
+ OUTPUT_MODULE_LOCATION module_location
+ OUTPUT_MODULE_TARGET dependency_target
+ )
+ get_filename_component(module_import_path "${module_location}" DIRECTORY)
+ list(APPEND all_qml_import_paths "${module_import_path}")
+
+ if (NOT "${import_version}" STREQUAL "")
set_property(TARGET ${target} APPEND PROPERTY
- QT_QML_MODULE_${import_set} "${import}"
+ QT_QML_MODULE_${import_set} "${import_uri} ${import_version}"
)
else()
- string(SUBSTRING ${import} 0 ${slash_position} import_module)
- math(EXPR slash_position "${slash_position} + 1")
- string(SUBSTRING ${import} ${slash_position} -1 import_version)
- if (import_version MATCHES "^([0-9]+(\\.[0-9]+)?|auto)$")
- set_property(TARGET ${target} APPEND PROPERTY
- QT_QML_MODULE_${import_set} "${import_module} ${import_version}"
- )
- else()
- message(FATAL_ERROR
- "Invalid module ${import} version number. "
- "Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'."
- )
- endif()
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_QML_MODULE_${import_set} "${import_uri}"
+ )
endif()
+ if(TARGET "${dependency_target}")
+ list(APPEND all_dependency_targets "${dependency_target}")
+ endif()
+ set(target_keyword_was_set FALSE)
endforeach()
endforeach()
foreach(dependency IN LISTS arg_DEPENDENCIES)
- string(FIND ${dependency} "/" slash_position REVERSE)
- if (slash_position EQUAL -1)
+
+ if (dependency STREQUAL "TARGET")
+ if (target_is_keyword)
+ set(target_keyword_was_set TRUE)
+ continue()
+ else()
+ message(AUTHOR_WARNING "TARGET is treated as a URI because QTP0005 is set to OLD. This is deprecated behavior. Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0005.html for policy details.")
+ set(target_keyword_was_set FALSE)
+ endif()
+ endif()
+ _qt_internal_parse_qml_module_dependency(${dependency} "${target_keyword_was_set}"
+ OUTPUT_URI dep_uri
+ OUTPUT_VERSION dep_version
+ OUTPUT_MODULE_LOCATION module_location
+ OUTPUT_MODULE_TARGET dependency_target
+ )
+ get_filename_component(module_import_path "${module_location}" DIRECTORY)
+ list(APPEND all_qml_import_paths "${module_import_path}")
+ if (NOT "${dep_version}" STREQUAL "")
set_property(TARGET ${target} APPEND PROPERTY
- QT_QML_MODULE_DEPENDENCIES "${dependency}"
+ QT_QML_MODULE_DEPENDENCIES "${dep_uri} ${dep_version}"
)
else()
- string(SUBSTRING ${dependency} 0 ${slash_position} dep_module_uri)
- math(EXPR slash_position "${slash_position} + 1")
- string(SUBSTRING ${dependency} ${slash_position} -1 dep_version)
- if (dep_version MATCHES "^([0-9]+(\\.[0-9]+)?|auto)$")
- set_property(TARGET ${target} APPEND PROPERTY
- QT_QML_MODULE_DEPENDENCIES "${dep_module_uri} ${dep_version}"
- )
- else()
- message(FATAL_ERROR
- "Invalid module dependency version number. "
- "Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'."
- )
- endif()
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_QML_MODULE_DEPENDENCIES "${dep_uri}"
+ )
+ endif()
+ set(target_keyword_was_set FALSE)
+ if(TARGET "${dependency_target}")
+ list(APPEND all_dependency_targets "${dependency_target}")
endif()
endforeach()
+ ### TODO: add support for transitive dependencies, too
+ list(REMOVE_DUPLICATES all_dependency_targets)
+ set_property(TARGET ${target} PROPERTY QT_QML_DEPENDENT_QML_MODULE_TARGETS "${all_dependency_targets}")
_qt_internal_collect_qml_module_dependencies(${target})
if(arg_AUTO_RESOURCE_PREFIX)
@@ -483,6 +646,8 @@ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
endif()
endif()
+ list(REMOVE_DUPLICATES all_qml_import_paths)
+
set_target_properties(${target} PROPERTIES
QT_QML_MODULE_NO_LINT "${arg_NO_LINT}"
QT_QML_MODULE_NO_CACHEGEN "${arg_NO_CACHEGEN}"
@@ -512,7 +677,7 @@ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
QT_QML_MODULE_PAST_MAJOR_VERSIONS "${arg_PAST_MAJOR_VERSIONS}"
# TODO: Check how this is used by qt6_android_generate_deployment_settings()
- QT_QML_IMPORT_PATH "${arg_IMPORT_PATH}"
+ QT_QML_IMPORT_PATH "${all_qml_import_paths}"
)
if(arg_TYPEINFO)
@@ -748,7 +913,7 @@ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
cmake_language(DEFER GET_CALL qmlls_ini_generation_id call)
if("${call}" STREQUAL "")
cmake_language(EVAL CODE
- "cmake_language(DEFER ID qmlls_ini_generation_id CALL _qt_internal_write_deferred_qmlls_ini_file)"
+ "cmake_language(DEFER ID qmlls_ini_generation_id CALL _qt_internal_write_deferred_qmlls_ini_file ${target})"
)
endif()
else()
@@ -759,9 +924,91 @@ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
endif()
endif()
endif()
+
+ if((backing_target_type STREQUAL "EXECUTABLE") AND (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.19.0"))
+ set_property(
+ DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ APPEND
+ PROPERTY QT_QML_TARGETS_FOR_DEFERRED_QTCONF_WRITEOUT
+ ${target}
+ )
+ get_directory_property(is_qtconf_writeout_scheduled DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} QT_QML_BUILDDIR_QTCONF_DEFERRED)
+ if (NOT is_qtconf_writeout_scheduled)
+ set_property(
+ DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ PROPERTY QT_QML_BUILDDIR_QTCONF_DEFERRED TRUE
+ )
+
+ cmake_language(EVAL CODE "
+ cmake_language(DEFER DIRECTORY [[${PROJECT_SOURCE_DIR}]]
+ CALL _qt_internal_write_deferred_builddir_qtconf [[${CMAKE_CURRENT_BINARY_DIR}]])
+ ")
+ endif()
+ endif()
+
+ if("${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.19.0" AND NOT CMAKE_GENERATOR STREQUAL "Xcode")
+ set(id qmlaotstats_aggregation)
+ cmake_language(DEFER DIRECTORY ${PROJECT_BINARY_DIR} GET_CALL ${id} call)
+
+ if("${call}" STREQUAL "")
+ cmake_language(EVAL CODE "cmake_language(DEFER DIRECTORY ${PROJECT_BINARY_DIR} "
+ "ID ${id} CALL _qt_internal_deferred_aggregate_aotstats_files ${target})")
+ endif()
+ else()
+ if(NOT TARGET all_aotstats)
+ if(CMAKE_GENERATOR STREQUAL "Xcode") #TODO: QTBUG-125995
+ add_custom_target(
+ all_aotstats
+ ${CMAKE_COMMAND} -E echo "aotstats is not supported on Xcode"
+ )
+ else()
+ add_custom_target(
+ all_aotstats
+ ${CMAKE_COMMAND} -E echo "aotstats is not supported on CMake versions < 3.19"
+ )
+ endif()
+ endif()
+ endif()
endfunction()
-function(_qt_internal_write_deferred_qmlls_ini_file)
+function(_qt_internal_deferred_aggregate_aotstats_files target)
+ get_property(module_aotstats_files GLOBAL PROPERTY "module_aotstats_files")
+ list(JOIN module_aotstats_files "\n" lines)
+ set(aotstats_list_file "${PROJECT_BINARY_DIR}/.rcc/qmlcache/all_aotstats.aotstatslist")
+ file(WRITE ${aotstats_list_file} ${lines})
+
+ set(all_aotstats_file ${PROJECT_BINARY_DIR}/.rcc/qmlcache/all_aotstats.aotstats)
+ set(formatted_stats_file ${PROJECT_BINARY_DIR}/.rcc/qmlcache/all_aotstats.txt)
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ add_custom_command(
+ OUTPUT
+ ${all_aotstats_file}
+ ${formatted_stats_file}
+ DEPENDS ${module_aotstats_files}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Qt6::qmlaotstats>
+ aggregate
+ ${aotstats_list_file}
+ ${all_aotstats_file}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Qt6::qmlaotstats>
+ format
+ ${all_aotstats_file}
+ ${formatted_stats_file}
+ )
+
+ if(NOT TARGET all_aotstats)
+ add_custom_target(all_aotstats
+ DEPENDS ${formatted_stats_file}
+ COMMAND ${CMAKE_COMMAND} -E cat ${formatted_stats_file}
+ )
+ endif()
+endfunction()
+
+function(_qt_internal_write_deferred_qmlls_ini_file target)
set(qmlls_ini_file "${CMAKE_CURRENT_SOURCE_DIR}/.qmlls.ini")
get_directory_property(_qmlls_ini_build_folders _qmlls_ini_build_folders)
list(REMOVE_DUPLICATES _qmlls_ini_build_folders)
@@ -772,8 +1019,11 @@ function(_qt_internal_write_deferred_qmlls_ini_file)
# cmake list separator and windows path separator are both ';', so no replacement needed
set(concatenated_build_dirs "${_qmlls_ini_build_folders}")
endif()
- set(file_content "[General]\nbuildDir=${concatenated_build_dirs}\nno-cmake-calls=false\n")
+ set(file_content "[General]\n")
+ string(APPEND file_content "buildDir=${concatenated_build_dirs}\n")
+ string(APPEND file_content "no-cmake-calls=false\n")
file(CONFIGURE OUTPUT "${qmlls_ini_file}" CONTENT "${file_content}")
+ _add_documentation_path_to_qmlls_ini_file(${target} ${qmlls_ini_file})
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
@@ -786,6 +1036,35 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endfunction()
endif()
+function(_add_documentation_path_to_qmlls_ini_file target qmlls_ini_file)
+ get_target_property(qtpaths ${QT_CMAKE_EXPORT_NAMESPACE}::qtpaths LOCATION)
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ set(docPath "${CMAKE_CURRENT_BINARY_DIR}/.docPath.tmp")
+ add_custom_command(
+ OUTPUT
+ ${docPath}
+ COMMAND
+ ${CMAKE_COMMAND} -E echo_append "docDir=" >> ${docPath};
+ COMMAND
+ ${tool_wrapper}
+ ${qtpaths}
+ --query QT_INSTALL_DOCS >> ${docPath}
+ COMMENT "Querying Qt documentation path"
+ VERBATIM
+ )
+ add_custom_target(${target}_custom ALL
+ DEPENDS ${docPath}
+ COMMAND
+ ${CMAKE_COMMAND} -E cat ${docPath} >> ${qmlls_ini_file}
+ COMMAND
+ ${CMAKE_COMMAND} -E rm -rf -- ${docPath}
+ COMMENT "Adding Qt documentation path to .qmlls.ini"
+ VERBATIM
+ )
+ add_dependencies(${target} ${target}_custom)
+
+endfunction()
+
# Make the prefix conform to the following:
# - Starts with a "/"
# - Does not end with a "/" unless the prefix is exactly "/"
@@ -2395,6 +2674,8 @@ function(qt6_target_qml_sources target)
"$<${have_direct_calls}:--direct-calls>"
"$<${have_arguments}:${arguments}>"
${qrc_resource_args}
+ "--dump-aot-stats"
+ "--module-id=${arg_URI}(${target})"
)
# For direct evaluation in if() below
@@ -2551,6 +2832,23 @@ function(qt6_target_qml_sources target)
"and .mjs. This leads to unexpected component names."
)
endif()
+ if(qml_file_ext AND qml_file_ext STREQUAL ".js" AND skip_qmldir STREQUAL "NOTFOUND")
+ file(
+ STRINGS ${qml_file_src} pragma_library
+ REGEX "^\\.pragma library$"
+ LIMIT_COUNT 1
+ LIMIT_INPUT 128
+ )
+ if(NOT pragma_library)
+ message(AUTHOR_WARNING
+ "${qml_file_src} is not an ECMAScript module and also doesn't contain "
+ "'.pragma library'. It will be re-evaluated in the context of every "
+ "QML document that explicitly or implicitly imports ${uri}. Set its "
+ "QT_QML_SKIP_QMLDIR_ENTRY source file property to FALSE if you really "
+ "want this to happen. Set it to TRUE to prevent it."
+ )
+ endif()
+ endif()
# We previously accepted the singular form of this property name
# during tech preview. Issue a warning for that, but still
@@ -2605,6 +2903,17 @@ function(qt6_target_qml_sources target)
set_property(TARGET ${target} APPEND_STRING PROPERTY
_qt_internal_qmldir_content "${qmldir_file_contents}"
)
+
+ if(ANDROID AND QT_ANDROID_GENERATE_JAVA_QML_COMPONENTS)
+ get_source_file_property(qml_file_generate_java_classes ${qml_file_src}
+ QT_QML_GENERATE_JAVA_CLASS
+ )
+ if(qml_file_generate_java_classes)
+ get_target_property(qml_module_uri ${target} QT_QML_MODULE_URI)
+ set_property(TARGET ${target} APPEND PROPERTY
+ _qt_qml_files_for_java_generator "${qml_module_uri}.${qml_file_typename}")
+ endif()
+ endif()
endif()
endif()
@@ -2641,9 +2950,17 @@ function(qt6_target_qml_sources target)
set(qmlcachegen_cmd "${qmlcachegen}")
endif()
+ set(aotstats_file "")
+ if("${qml_file_src}" MATCHES ".+\\.qml")
+ set(aotstats_file "${compiled_file}.aotstats")
+ list(APPEND aotstats_files ${aotstats_file})
+ endif()
+
_qt_internal_get_tool_wrapper_script_path(tool_wrapper)
add_custom_command(
- OUTPUT ${compiled_file}
+ OUTPUT
+ ${compiled_file}
+ ${aotstats_file}
COMMAND ${CMAKE_COMMAND} -E make_directory ${out_dir}
COMMAND
${tool_wrapper}
@@ -2687,6 +3004,29 @@ function(qt6_target_qml_sources target)
endif()
endforeach()
+ if(NOT "${arg_URI}" STREQUAL "")
+ list(JOIN aotstats_files "\n" aotstats_files_lines)
+ set(module_aotstats_list_file "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qmlcache/module_${arg_URI}.aotstatslist")
+ file(WRITE ${module_aotstats_list_file} ${aotstats_files_lines})
+
+ # Aggregate qml file aotstats into module-level aotstats
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ set(output "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qmlcache/module_${arg_URI}.aotstats")
+ add_custom_command(
+ OUTPUT ${output}
+ DEPENDS ${aotstats_files}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Qt6::qmlaotstats>
+ aggregate
+ ${module_aotstats_list_file}
+ ${output}
+ )
+
+ # Collect module-level aotstats files for later aggregation at the project level
+ set_property(GLOBAL APPEND PROPERTY "module_aotstats_files" ${output})
+ endif()
+
if(ANDROID)
_qt_internal_collect_qml_root_paths("${target}" ${arg_QML_FILES})
endif()
@@ -3817,9 +4157,30 @@ endif()")
# imports deployed to the bundle anyway, the build RPATHs will allow
# the regular libraries, frameworks and non-QML plugins to still be
# found, even if they are outside the app bundle.
+
+ # Support Xcode, which places the application build dir into a configuration specific
+ # subdirectory. Override both the deploy prefix and install prefix, because we
+ # differentiate them in the qml installation implementation due to ENV{DESTDIR}
+ # handling.
+ set(deploy_path_suffix "")
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config)
+ set(deploy_path_suffix "/$<CONFIG>")
+ endif()
+
+ set(target_binary_dir_with_config_prefix
+ "$<TARGET_PROPERTY:${arg_TARGET},BINARY_DIR>${deploy_path_suffix}")
+
+ set(post_build_install_prefix
+ "CMAKE_INSTALL_PREFIX=${target_binary_dir_with_config_prefix}")
+
+ set(post_build_deploy_prefix
+ "QT_DEPLOY_PREFIX=${target_binary_dir_with_config_prefix}")
+
add_custom_command(TARGET ${arg_TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND}
- -D "QT_DEPLOY_PREFIX=$<TARGET_PROPERTY:${arg_TARGET},BINARY_DIR>"
+ -D "${post_build_install_prefix}"
+ -D "${post_build_deploy_prefix}"
-D "__QT_DEPLOY_IMPL_DIR=${deploy_impl_dir}"
-D "__QT_DEPLOY_POST_BUILD=TRUE"
-P "${post_build_deploy_script}"
diff --git a/src/qml/Qt6qt.conf.in b/src/qml/Qt6qt.conf.in
new file mode 100644
index 0000000000..10a7dcab50
--- /dev/null
+++ b/src/qml/Qt6qt.conf.in
@@ -0,0 +1,5 @@
+[Paths]
+QmlImports = @qt_all_qml_output_dirs@
+
+[Config]
+MergeQtConf = true
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
index 04b47e3ae5..7e0fb00021 100644
--- a/src/qml/animations/qabstractanimationjob_p.h
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -193,7 +193,11 @@ public:
void updateAnimationsTime(qint64 timeStep) override;
//useful for profiling/debugging
+#ifdef QT_QAbstractAnimationTimer_runningAnimationCount_IS_CONST
+ qsizetype runningAnimationCount() const override { return animations.size(); }
+#else
int runningAnimationCount() override { return animations.size(); }
+#endif
bool hasStartAnimationPending() const { return startAnimationPending; }
diff --git a/src/qml/common/qv4alloca_p.h b/src/qml/common/qv4alloca_p.h
index c1d1e6e87d..51c99192d3 100644
--- a/src/qml/common/qv4alloca_p.h
+++ b/src/qml/common/qv4alloca_p.h
@@ -17,16 +17,17 @@
#include <QtCore/private/qglobal_p.h>
-#if QT_CONFIG(alloca_h)
+#include <stdlib.h>
+#if __has_include(<alloca.h>)
# include <alloca.h>
-#elif QT_CONFIG(alloca_malloc_h)
+#endif
+#if __has_include(<malloc.h>)
# include <malloc.h>
+#endif
+
+#ifdef Q_CC_MSVC
// This does not matter unless compiling in strict standard mode.
-# ifdef Q_CC_MSVC
-# define alloca _alloca
-# endif
-#else
-# include <stdlib.h>
+# define alloca _alloca
#endif
// Define Q_ALLOCA_VAR macro to be used instead of #ifdeffing
@@ -37,7 +38,7 @@
Q_ALLOCA_DECLARE(type, name); \
Q_ALLOCA_ASSIGN(type, name, size)
-#if QT_CONFIG(alloca)
+#ifdef alloca
#define Q_ALLOCA_DECLARE(type, name) \
type *name = 0
@@ -46,27 +47,16 @@
name = static_cast<type*>(alloca(size))
#else
-QT_BEGIN_NAMESPACE
-class Qt_AllocaWrapper
-{
-public:
- Qt_AllocaWrapper() { m_data = 0; }
- ~Qt_AllocaWrapper() { free(m_data); }
- void *data() { return m_data; }
- void allocate(int size) { m_data = malloc(size); memset(m_data, 0, size); }
-private:
- void *m_data;
-};
-QT_END_NAMESPACE
+# include <memory>
#define Q_ALLOCA_DECLARE(type, name) \
- Qt_AllocaWrapper _qt_alloca_##name; \
+ std::unique_ptr<char[]> _qt_alloca_##name; \
type *name = nullptr
#define Q_ALLOCA_ASSIGN(type, name, size) \
do { \
- _qt_alloca_##name.allocate(size); \
- name = static_cast<type*>(_qt_alloca_##name.data()); \
+ _qt_alloca_##name.reset(new char[size]); \
+ name = reinterpret_cast<type*>(_qt_alloca_##name.get()); \
} while (false)
#endif
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index 79df230872..c21fc19fa9 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -1227,6 +1227,7 @@ struct Unit
NativeMethodsAcceptThisObject = 0x800,
ValueTypesCopied = 0x1000,
ValueTypesAddressable = 0x2000,
+ ValueTypesAssertable = 0x4000,
};
quint32_le flags;
quint32_le stringTableSize;
@@ -1706,6 +1707,11 @@ public:
return unitData()->flags & CompiledData::Unit::ValueTypesAddressable;
}
+ bool valueTypesAreAssertable() const
+ {
+ return unitData()->flags & CompiledData::Unit::ValueTypesAssertable;
+ }
+
bool componentsAreBound() const
{
return unitData()->flags & CompiledData::Unit::ComponentsBound;
diff --git a/src/qml/common/qv4staticvalue_p.h b/src/qml/common/qv4staticvalue_p.h
index e887cdc674..9b4f582c00 100644
--- a/src/qml/common/qv4staticvalue_p.h
+++ b/src/qml/common/qv4staticvalue_p.h
@@ -366,10 +366,10 @@ struct StaticValue
QV4_NEARLY_ALWAYS_INLINE void setDouble(double d) {
if (qt_is_nan(d)) {
// We cannot store just any NaN. It has to be a NaN with only the quiet bit
- // set in the upper bits of the mantissa and the sign bit off.
+ // set in the upper bits of the mantissa and the sign bit either on or off.
// qt_qnan() happens to produce such a thing via std::numeric_limits,
// but this is actually not guaranteed. Therefore, we make our own.
- _val = (quint64(QuickType::NaN) << Tag_Shift);
+ _val = (quint64(std::signbit(d) ? QuickType::MinusNaN : QuickType::NaN) << Tag_Shift);
Q_ASSERT(isNaN());
} else {
memcpy(&_val, &d, 8);
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index a81f8fb1d8..72111b3138 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -861,6 +861,15 @@ private:
return true;
}
+ if (value == "Inassertable"_L1) {
+ setFlag(Pragma::Assertable, false);
+ return true;
+ }
+ if (value == "Assertable"_L1) {
+ setFlag(Pragma::Assertable, true);
+ return true;
+ }
+
return false;
});
}
@@ -1718,6 +1727,10 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
.testFlag(Pragma::Addressable)) {
createdUnit->flags |= Unit::ValueTypesAddressable;
}
+ if (Pragma::ValueTypeBehaviorValues(p->valueTypeBehavior)
+ .testFlag(Pragma::Assertable)) {
+ createdUnit->flags |= Unit::ValueTypesAssertable;
+ }
break;
case Pragma::Translator:
if (createdUnit->translationTableSize)
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 546d1fac58..ffd3ad72f7 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -443,6 +443,7 @@ struct Q_QML_COMPILER_EXPORT Pragma
{
Copy = 0x1,
Addressable = 0x2,
+ Assertable = 0x4,
};
Q_DECLARE_FLAGS(ValueTypeBehaviorValues, ValueTypeBehaviorValue);
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 25831eab73..8a81bc98f9 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -30,8 +30,8 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-Q_LOGGING_CATEGORY(lcQmlUsedBeforeDeclared, "qt.qml.usedbeforedeclared");
-Q_LOGGING_CATEGORY(lcQmlInjectedParameter, "qt.qml.injectedparameter");
+Q_STATIC_LOGGING_CATEGORY(lcQmlUsedBeforeDeclared, "qt.qml.usedbeforedeclared");
+Q_STATIC_LOGGING_CATEGORY(lcQmlInjectedParameter, "qt.qml.injectedparameter");
using namespace QV4;
using namespace QV4::Compiler;
diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf
index 9c1632e537..857cd41ff8 100644
--- a/src/qml/doc/qtqml.qdocconf
+++ b/src/qml/doc/qtqml.qdocconf
@@ -2,7 +2,7 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
include($QT_INSTALL_DOCS/config/exampleurl-qtdeclarative.qdocconf)
project = QtQml
-description = Qt QML Reference Documentation
+description = Qt Qml Reference Documentation
version = $QT_VERSION
examplesinstallpath = qml
@@ -12,19 +12,19 @@ qhp.projects = QtQml
qhp.QtQml.file = qtqml.qhp
qhp.QtQml.namespace = org.qt-project.qtqml.$QT_VERSION_TAG
qhp.QtQml.virtualFolder = qtqml
-qhp.QtQml.indexTitle = Qt QML
+qhp.QtQml.indexTitle = Qt Qml
qhp.QtQml.indexRoot =
qhp.QtQml.subprojects = qmltypes classes examples
qhp.QtQml.subprojects.classes.title = C++ Classes
-qhp.QtQml.subprojects.classes.indexTitle = Qt QML C++ Classes
-qhp.QtQml.subprojects.classes.selectors = class fake:headerfile
+qhp.QtQml.subprojects.classes.indexTitle = Qt Qml C++ Classes
+qhp.QtQml.subprojects.classes.selectors = class headerfile
qhp.QtQml.subprojects.classes.sortPages = true
qhp.QtQml.subprojects.examples.title = Examples
-qhp.QtQml.subprojects.examples.indexTitle = Qt QML Examples
-qhp.QtQml.subprojects.examples.selectors = fake:example
+qhp.QtQml.subprojects.examples.indexTitle = Qt Qml Examples
+qhp.QtQml.subprojects.examples.selectors = example
qhp.QtQml.subprojects.qmltypes.title = QML Types
-qhp.QtQml.subprojects.qmltypes.indexTitle = Qt QML QML Types
+qhp.QtQml.subprojects.qmltypes.indexTitle = Qt Qml QML Types
qhp.QtQml.subprojects.qmltypes.selectors = qmlclass
qhp.QtQml.subprojects.qmltypes.sortPages = true
@@ -60,9 +60,9 @@ manifestmeta.thumbnail.names += "QtQml/Chapter 4*" \
"QtQml/Chapter 6*" \
"QtQml/C++ Extensions: *"
-navigation.landingpage = "Qt QML"
-navigation.cppclassespage = "Qt QML C++ Classes"
-navigation.qmltypespage = "Qt QML QML Types"
+navigation.landingpage = "Qt Qml"
+navigation.cppclassespage = "Qt Qml C++ Classes"
+navigation.qmltypespage = "Qt Qml QML Types"
# Auto-generate navigation linking based on the \list structures on the following:
navigation.toctitles = "Qt Quick Compiler"
diff --git a/src/qml/doc/snippets/qml/function-call-binding.qml b/src/qml/doc/snippets/qml/function-call-binding.qml
new file mode 100644
index 0000000000..1dc7d0224c
--- /dev/null
+++ b/src/qml/doc/snippets/qml/function-call-binding.qml
@@ -0,0 +1,18 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+//! [rectangle]
+Rectangle {
+ x: rectPosition()
+ y: rectPosition()
+ width: 200
+ height: 200
+ color: "lightblue"
+
+ function rectPosition() {
+ return enabled ? 0 : 100
+ }
+}
+//! [rectangle]
diff --git a/src/qml/doc/src/cmake/cmake-properties.qdoc b/src/qml/doc/src/cmake/cmake-properties.qdoc
index 297a094582..a2ca59efc8 100644
--- a/src/qml/doc/src/cmake/cmake-properties.qdoc
+++ b/src/qml/doc/src/cmake/cmake-properties.qdoc
@@ -206,3 +206,24 @@ C++ during qmltc compilation.
\sa{qmltc-cmake}
*/
+
+/*!
+\page cmake-source-file-property-qt-qml-generate-java-class.html
+\ingroup cmake-source-file-properties-qtqml
+\ingroup cmake-android-build-properties
+
+\title QT_QML_GENERATE_JAVA_CLASS
+
+\summary {Marks a QML file for Java code generation.}
+
+\cmakepropertysince 6.8
+When using QML as a \l {Android: View} in Android via \l QtQuickView, you can choose
+the QML components to make available as generated Java classes usable from Android code.
+To mark a \c {.qml} file for code generation, set its \c QT_QML_GENERATE_JAVA_CLASS
+source property to \c TRUE. The source property must be set before
+\l {qt_add_qml_module}{creating} the module. The file should start with an uppercase
+letter and define a QML component. This property is valid only if
+\l QT_ANDROID_GENERATE_JAVA_QML_COMPONENTS is defined.
+
+\sa {Naming Custom QML Object Types}
+*/
diff --git a/src/qml/doc/src/cmake/policy/qtp0005.qdoc b/src/qml/doc/src/cmake/policy/qtp0005.qdoc
new file mode 100644
index 0000000000..25d5175789
--- /dev/null
+++ b/src/qml/doc/src/cmake/policy/qtp0005.qdoc
@@ -0,0 +1,42 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-cmake-policy-qtp0005.html
+\ingroup qt-cmake-policies
+
+\title QTP0005
+\keyword qt_cmake_policy_qtp0005
+
+\summary {qt_add_qml_module's DEPENDENCIES argument accepts targets}
+
+This policy was introduced in Qt 6.8. It allows passing targets to
+\l{qt_add_qml_module}{qt_add_qml_module()} \c DEPENDENCIES, \c IMPORTS, \c
+OPTIONAL_IMPORTS and \c DEFAULT_IMPORTS.
+
+Enabling this policy means that the arguments which are passed to the key words
+can be prefixed with TARGET, and are then treated as a target name.
+
+The \c OLD behavior of this policy is that the "TARGET name" is treated as two
+URIs, "TARGET" and "name".
+
+The \c NEW behavior of this policy is that \c TARGET is considered a keyword,
+and the URI is extracted from the target which follows next. It is a hard error
+if the name following \c TARGET does not name a target, or if that target does
+not correspond to a QML module.
+
+In both the \c NEW and the \c OLD behavior it is possible to specify a module
+version by appending a slash and the version. See
+\l{Declaring module dependencies} for more details.
+
+Qt 6.8 issues warnings if you pass a URI to \c DEPENDENCIES which coincides
+with a target name.
+Use the \l qt_policy command to suppress the warning by explicitly setting
+the policy to \c OLD or \c NEW.
+
+\qtpolicydeprecatedbehavior
+
+\sa qt_policy, {qt6_standard_project_setup}{qt_standard_project_setup()},
+ qt_cmake_policies, qt_add_qml_module
+
+*/
diff --git a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
index 4ca7635b9c..63f9707d4d 100644
--- a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
+++ b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
@@ -578,6 +578,9 @@ These additional targets are generated internally by \c{qt_add_qml_module()}
and are referenced by the backing target's linking requirements as part of
ensuring that resources are set up and loaded correctly.
+\note Since Qt 6.8, it is possible to pass a target name to IMPORTS and
+DEPENDENCIES. See \l{QTP0005} for more details.
+
\target PLUGIN_TARGET
\section2 Targets and plugin targets
diff --git a/src/qml/doc/src/cmake/qt_target_qml_sources.qdoc b/src/qml/doc/src/cmake/qt_target_qml_sources.qdoc
index 336cd973f9..6f06de48e7 100644
--- a/src/qml/doc/src/cmake/qt_target_qml_sources.qdoc
+++ b/src/qml/doc/src/cmake/qt_target_qml_sources.qdoc
@@ -136,10 +136,15 @@ file will still be added to the \c target as a resource in uncompiled form
(see \l{qmlcachegen-auto}{Caching compiled QML sources}).
Set the \c QT_QML_SKIP_QMLDIR_ENTRY source file property to \c TRUE to prevent
-that \c{.qml} file from being added as a type to the QML module's typeinfo file
-(see \l{qmldir-autogeneration}{Auto-generating \c{qmldir} and typeinfo files}).
-This would normally only be used for a file that does not expose a public type,
-such as a private JS file.
+that QML or JavaScript file from being added as a type to the QML module's
+\c{qmldir} file (see \l{qmldir-autogeneration}{Auto-generating \c{qmldir} and
+typeinfo files}). This would normally be used for a file that does not expose
+a public type, such as a private JavaScript file. For JavaScript files with
+upper case names that are neither ECMAScript modules nor declared as stateless
+libraries via \c{.pragma library} you should consider this option. If you
+include them in the \c{qmldir} file, they are re-evaluated in the scope of
+every QML document that explicitly or implicitly imports the module they
+belong to.
By default, when \l{qmldir-autogeneration}{generating the \c qmldir file}, a
single type entry will be generated for each \c{.qml} file that provides a type.
diff --git a/src/qml/doc/src/cppclasses/topic.qdoc b/src/qml/doc/src/cppclasses/topic.qdoc
index 78595fa13a..b440ca437d 100644
--- a/src/qml/doc/src/cppclasses/topic.qdoc
+++ b/src/qml/doc/src/cppclasses/topic.qdoc
@@ -2,13 +2,13 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtqml-cppclasses-topic.html
-\title Important C++ Classes Provided By The Qt QML Module
-\brief Overview of the C++ classes provided by the Qt QML module
+\title Important C++ Classes Provided By The Qt Qml Module
+\brief Overview of the C++ classes provided by the Qt Qml module.
The \l{Qt Qml} module provides C++ classes which implement the QML framework.
Clients can use these classes to interact with the QML run-time (for example,
by injecting data or invoking methods on objects), and to instantiate a
-hierarchy of objects from a QML document. The Qt QML module provides more
+hierarchy of objects from a QML document. The Qt Qml module provides more
C++ API than just the classes listed here, however the classes listed here
provide the foundations of the QML runtime and the core concepts of QML.
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index 2822f4acee..4932943fc1 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -307,7 +307,7 @@ calling its \l {QDateTime::}{time()} method.
\section2 Sequence Type to JavaScript Array
See \l{QML Sequence Types} for a general description of sequence types. The
-\l{Qt QML QML Types}{QtQml module} contains a few sequence types
+\l{Qt Qml QML Types}{QtQml module} contains a few sequence types
you may want to use.
You can also create a list-like data structure by constructing a QJSValue using
diff --git a/src/qml/doc/src/external-resources.qdoc b/src/qml/doc/src/external-resources.qdoc
index ac22729d63..7cefe05952 100644
--- a/src/qml/doc/src/external-resources.qdoc
+++ b/src/qml/doc/src/external-resources.qdoc
@@ -29,6 +29,10 @@
\title QmlLive Manual
*/
/*!
+ \externalpage https://felgo.com/qml-hot-reload
+ \title Felgo QML Hot Reload Tool
+*/
+/*!
\externalpage https://doc.qt.io/qtcreator/creator-debugging-qml.html
\title Qt Creator: QML Debugger
*/
@@ -73,4 +77,8 @@
\externalpage https://developer.android.com/topic/libraries/view-binding
\title Android: View binding
*/
+/*!
+ \externalpage https://developer.android.com/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW
+ \title Android: SYSTEM_ALERT_WINDOW
+*/
diff --git a/src/qml/doc/src/javascript/qmlglobalobject.qdoc b/src/qml/doc/src/javascript/qmlglobalobject.qdoc
index 15b9996ff3..1bd03fad54 100644
--- a/src/qml/doc/src/javascript/qmlglobalobject.qdoc
+++ b/src/qml/doc/src/javascript/qmlglobalobject.qdoc
@@ -13,8 +13,8 @@ additional imports:
\list
\li The \l{QmlGlobalQtObject}{Qt object}: A QML object that offers helper methods
and properties specific to the QML environment.
-\li \l {Qt::}{qsTr()}, \l {Qt::}{qsTranslate()}, \l {Qt::}{qsTrId()}, \l {Qt::}{qsTrNoOp()},
- \l {Qt::}{qsTranslateNoOp()}, \l {Qt::}{qsTrIdNoOp()} functions:
+\li \l {Qt::}{qsTr()}, \l {Qt::}{qsTranslate()}, \l {Qt::}{qsTrId()}, \l {Qt::}{QT_TR_NOOP()()},
+ \l {Qt::}{QT_TRANSLATE_NOOP()}, \l {Qt::}{QT_TRID_NOOP()} functions:
QML functions that let you translate \l{Mark Strings for Translation}
{strings} and \l{Mark Translatable Data Text Strings}{string literals} in the
QML environment.
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index ecb13f160d..470d4598fc 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -1459,6 +1459,10 @@
Returns -1 if no matching type was found or one of the given parameters
was invalid.
+ \note: qmlTypeId tries to make modules available, even if they were not accessed by any
+ engine yet. This can introduce overhead the first time a module is accessed. Trying to
+ find types from a module which does not exist always introduces this overhead.
+
\sa QML_ELEMENT, QML_NAMED_ELEMENT, QML_SINGLETON, qmlRegisterType(), qmlRegisterSingletonType()
*/
diff --git a/src/qml/doc/src/qmllanguageref/documents/structure.qdoc b/src/qml/doc/src/qmllanguageref/documents/structure.qdoc
index 5a43ae2028..72a6e08407 100644
--- a/src/qml/doc/src/qmllanguageref/documents/structure.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/structure.qdoc
@@ -215,12 +215,6 @@ QtObject {
}
\endqml
-If the type does not match, casting returns \c undefined. \c instanceof
-only checks for inheritance, not for all possible type coercions. So, for
-example, a \l{QRect} is not a \c rect value type since \c rect is \l{QRectF}
-in C++, and therefore not related by inheritance. With \c as you can cast
-to any type compatible via coercion.
-
Since \c rect in the above example is now a type name, it will shadow any
properties called \c{rect}.
@@ -231,6 +225,25 @@ able to. You can use \l{qmllint Reference}{qmllint} to find such occurrences.
There is also a \c{Inaddressable} value you can use to explicitly specify the
default behavior.
+Another attribute to the \c{ValueTypeBehavior} pragma is \c{Assertable},
+introduced in Qt 6.8. Due to a mistake in Qt 6.6 and 6.7 the \c{a as rect} above
+not only checks whether \c{a} is a \c{rect} but also constructs a \c{rect} if
+\c{a} is of a compatible type. This is obviously not what a type assertion
+should do. Specifying \c{Assertable} prevents this behavior and restricts type
+assertions for value types to only check for the type. You should always specify
+it if you are going to use value types with \c{as}. In any case, if the
+type assertion for a value type fails, the result is \c{undefined}.
+
+\c{instanceof} does not have this problem since it only checks for inheritance,
+not for all possible type coercions.
+
+\note Using \c{as} with the \c{int} and \c{double} types is not advisable since by
+JavaScript rules, the result of any calculation is a floating point number, even
+if it happens to hold the same value as its integer equivalent. Conversely, any
+integer constant you declare in JavaScript is not a double by QML's type mapping
+rules. Furthermore, \c{int} and \c{double} are reserved words. You can only
+address these types via type namespaces.
+
Value types and sequences are generally treated as references. This means, if
you retrieve a value type instance from a property into a local value, and then
change the local value, the original property is also changed. Furthermore,
diff --git a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
index 65e3b95f8e..b45ad83fb8 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
@@ -98,6 +98,13 @@ In the previous example,
\li \c bottomRect.color depends on \c myTextInput.text.length
\endlist
+In addition, any properties referenced within a JavaScript function that is
+itself used as a binding will be re-evaluated. For example, in the snippet
+below, whenever the \c enabled property of the \c Rectangle changes, the
+bindings for the \c x and \c y properties will be re-evaluated:
+
+\snippet qml/function-call-binding.qml rectangle
+
Syntactically, bindings are allowed to be of arbitrary complexity. However, if
a binding is overly complex - such as involving multiple lines, or imperative
loops - it could indicate that the binding is being used for more than describing
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc
index d332617b16..d4b09ab180 100644
--- a/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/typesystem/objecttypes.qdoc
@@ -98,7 +98,7 @@ See \l{qtqml-documents-scope.html}{Scope and Naming Resolution} for more details
\section1 Defining Object Types from C++
C++ plugin writers and application developers may register types defined in C++
-through API provided by the Qt QML module. There are various registration
+through API provided by the Qt Qml module. There are various registration
functions which each allow different use-cases to be fulfilled.
For more information about those registration functions, and the specifics of
exposing custom C++ types to QML, see the documentation regarding
diff --git a/src/qml/doc/src/qmlsingletons.qdoc b/src/qml/doc/src/qmlsingletons.qdoc
index ad441eca85..e5c95d4178 100644
--- a/src/qml/doc/src/qmlsingletons.qdoc
+++ b/src/qml/doc/src/qmlsingletons.qdoc
@@ -20,7 +20,7 @@ the singleton in a QML file, or register it from C++.
\section2 Defining singletons in QML
To define a singleton in QML, you first have to add
\code
-pragma singleton
+pragma Singleton
\endcode
to the top of your file.
There's one more step: You will need to add an entry to the QML module's
diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc
index e6896addf6..67dd6a9fea 100644
--- a/src/qml/doc/src/qmltypereference.qdoc
+++ b/src/qml/doc/src/qmltypereference.qdoc
@@ -3,9 +3,9 @@
/*!
\qmlmodule QtQml
-\title Qt QML QML Types
+\title Qt Qml QML Types
\ingroup qmlmodules
-\brief List of QML types provided by the Qt QML module
+\brief List of QML types provided by the Qt Qml module.
The \l{Qt Qml} module provides the definition and implementation of various
convenience types that can be used with the QML language. This includes
diff --git a/src/qml/doc/src/qtqml-cpp.qdoc b/src/qml/doc/src/qtqml-cpp.qdoc
index e337364489..236b90ab0a 100644
--- a/src/qml/doc/src/qtqml-cpp.qdoc
+++ b/src/qml/doc/src/qtqml-cpp.qdoc
@@ -2,12 +2,12 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\module QtQml
-\title Qt QML C++ Classes
+\title Qt Qml C++ Classes
\ingroup modules
\qtcmakepackage Qml
\qtvariable qml
-\brief The C++ API provided by the Qt QML module.
+\brief The C++ API provided by the Qt Qml module.
-For more information on the Qt QML module, see the
+For more information on the Qt Qml module, see the
\l{Qt Qml} module documentation.
*/
diff --git a/src/qml/doc/src/qtqml.qdoc b/src/qml/doc/src/qtqml.qdoc
index 51a638bf4d..f44a7130e6 100644
--- a/src/qml/doc/src/qtqml.qdoc
+++ b/src/qml/doc/src/qtqml.qdoc
@@ -12,7 +12,7 @@ with the \l{The QML Reference}{QML language}. It defines and implements the
language and engine infrastructure, and provides an API to enable application
developers to \l{Registering QML Types and QML Modules}{register} custom QML types
and modules and integrate QML code with JavaScript and C++. The Qt Qml module
-provides both a \l{Qt QML QML Types}{QML API} and a
+provides both a \l{Qt Qml QML Types}{QML API} and a
\l{Qt Qml C++ Classes}{C++ API}.
\section1 Using the Module
@@ -21,10 +21,10 @@ provides both a \l{Qt QML QML Types}{QML API} and a
\include {module-use.qdocinc} {using the qml api} {QtQml}
-The Qt QML module contains the QML framework and important QML types used in
+The Qt Qml module contains the QML framework and important QML types used in
applications. The constructs of QML are described in the \l{The QML Reference}.
-The \l{Qt QML QML Types}{QML API} of the Qt QML module provides a number of
+The \l{Qt Qml QML Types}{QML API} of the Qt Qml module provides a number of
\l{qtqml-typesystem-objecttypes.html}{QML Object Types},
\l{qtqml-typesystem-valuetypes.html}{QML Value Types} and namespaces.
@@ -33,7 +33,7 @@ The \l{Qt QML QML Types}{QML API} of the Qt QML module provides a number of
\include {module-use.qdocinc} {using the c++ api}
The C++ API contains some
-\l{Important C++ Classes Provided By The Qt QML Module}{important classes}
+\l{Important C++ Classes Provided By The Qt Qml Module}{important classes}
you should get familiar with. It also provides
\l{Integrating with JavaScript values from C++}{types} to hold JavaScript
values.
@@ -83,20 +83,20 @@ These articles contain information about Qt Qml.
\section1 Reference
\list
- \li \l {Qt QML C++ Classes} {C++ Classes}
- \li \l {Qt QML QML Types} {QML Types}
+ \li \l {Qt Qml C++ Classes} {C++ Classes}
+ \li \l {Qt Qml QML Types} {QML Types}
\endlist
\section1 Licenses and Attributions
-Qt QML is available under commercial licenses from \l{The Qt Company}.
+Qt Qml is available under commercial licenses from \l{The Qt Company}.
In addition, it is available under free software licenses. Since Qt 5.4,
these free software licenses are
\l{GNU Lesser General Public License, version 3}, or
the \l{GNU General Public License, version 2}.
See \l{Qt Licensing} for further details.
-Furthermore Qt QML in Qt \QtVersion may contain third party
+Furthermore Qt Qml in Qt \QtVersion may contain third party
modules under following permissive licenses:
\generatelist{groupsbymodule attributions-qtqml}
diff --git a/src/qml/doc/src/tools/qtqml-tooling-qmllint.qdoc b/src/qml/doc/src/tools/qtqml-tooling-qmllint.qdoc
index b26fe1eff0..7dfde85f2a 100644
--- a/src/qml/doc/src/tools/qtqml-tooling-qmllint.qdoc
+++ b/src/qml/doc/src/tools/qtqml-tooling-qmllint.qdoc
@@ -14,10 +14,11 @@ It also warns about some QML anti-patterns. If you want to disable a specific
warning type, you can find the appropriate flag for doing so by passing
\c{--help} on the command line.
-By default, some issues will result in warnings that will be printed and result
-in a non-zero exit code.
+By default, some issues will result in warnings that will be printed. If there
+are more warnings than a limit which can be configured with \c{--max-warnings},
+the exit code will be non-zero.
Minor issues however (such as unused imports) are just informational messages
-by default and will not affect the exit code.
+by default and will never affect the exit code.
qmllint is very configurable and allows for disabling warnings or changing how
they are treated.
Users may freely turn any issue into a warning, informational message, or
diff --git a/src/qml/jit/qv4assemblercommon.cpp b/src/qml/jit/qv4assemblercommon.cpp
index 2b33d0aa10..b18b4960b7 100644
--- a/src/qml/jit/qv4assemblercommon.cpp
+++ b/src/qml/jit/qv4assemblercommon.cpp
@@ -23,7 +23,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
-Q_LOGGING_CATEGORY(lcAsm, "qt.qml.v4.asm")
+Q_STATIC_LOGGING_CATEGORY(lcAsm, "qt.qml.v4.asm")
namespace {
class QIODevicePrintStream: public FilePrintStream
diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp
index 496624c752..ba681cdbf1 100644
--- a/src/qml/jit/qv4baselineassembler.cpp
+++ b/src/qml/jit/qv4baselineassembler.cpp
@@ -883,6 +883,20 @@ void BaselineAssembler::storeLocal(int index, int level)
--level;
}
pasm()->storeAccumulator(Address(PlatformAssembler::ScratchRegister, ctx.locals.offset + offsetof(ValueArray<0>, values) + sizeof(Value)*index));
+ // check if we need a write barrier
+ auto skipBarrier = pasm()->branch8(
+ PlatformAssembler::Equal,
+ PlatformAssembler::Address(PlatformAssembler::EngineRegister,
+ offsetof(EngineBase, isGCOngoing)),
+ TrustedImm32(0));
+ saveAccumulatorInFrame();
+ // if so, do a runtime call
+ pasm()->prepareCallWithArgCount(1);
+ pasm()->passAccumulatorAsArg(0);
+ pasm()->callRuntime((void*)Runtime::MarkCustom::call, CallResultDestination::Ignore);
+ loadAccumulatorFromFrame();
+ skipBarrier.link(pasm());
+
}
void BaselineAssembler::loadString(int stringId)
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index 40138ea700..85569d6218 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -33,10 +33,10 @@ class BaselineAssembler;
class BaselineJIT final: public Moth::ByteCodeHandler
{
public:
- BaselineJIT(QV4::Function *);
- ~BaselineJIT() override;
+ Q_AUTOTEST_EXPORT BaselineJIT(QV4::Function *);
+ Q_AUTOTEST_EXPORT ~BaselineJIT() override;
- void generate();
+ Q_AUTOTEST_EXPORT void generate();
void generate_Ret() override;
void generate_Debug() override;
diff --git a/src/qml/jsapi/qjsprimitivevalue.h b/src/qml/jsapi/qjsprimitivevalue.h
index 4ba3fd7dc3..3551eca358 100644
--- a/src/qml/jsapi/qjsprimitivevalue.h
+++ b/src/qml/jsapi/qjsprimitivevalue.h
@@ -355,11 +355,16 @@ public:
return leftInt % rightInt;
Q_FALLTHROUGH();
}
- default:
+ case Undefined:
+ case Null:
+ case Double:
+ case String:
break;
}
Q_FALLTHROUGH();
- default:
+ case Undefined:
+ case Double:
+ case String:
break;
}
@@ -706,9 +711,18 @@ private:
{
switch (type()) {
case Undefined: return true;
+ case Null: return false;
+ case Boolean: return false;
+ case Integer: return false;
case Double: return std::isnan(asDouble());
- default: return false;
+ case String: return false;
}
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+ #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN(false);
+ #else
+ return false;
+ #endif
}
struct QJSPrimitiveValuePrivate
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index f2be552cf8..a49bd32d66 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -12,14 +12,14 @@ DEFINE_OBJECT_VTABLE(ArrayBufferCtor);
DEFINE_OBJECT_VTABLE(SharedArrayBuffer);
DEFINE_OBJECT_VTABLE(ArrayBuffer);
-void Heap::SharedArrayBufferCtor::init(QV4::ExecutionContext *scope)
+void Heap::SharedArrayBufferCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("SharedArrayBuffer"));
+ Heap::FunctionObject::init(engine, QStringLiteral("SharedArrayBuffer"));
}
-void Heap::ArrayBufferCtor::init(QV4::ExecutionContext *scope)
+void Heap::ArrayBufferCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("ArrayBuffer"));
+ Heap::FunctionObject::init(engine, QStringLiteral("ArrayBuffer"));
}
ReturnedValue SharedArrayBufferCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index aafa3c6335..af1195a947 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -25,11 +25,11 @@ namespace QV4 {
namespace Heap {
struct SharedArrayBufferCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
struct ArrayBufferCtor : SharedArrayBufferCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
struct Q_QML_EXPORT SharedArrayBuffer : Object {
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index e1da807c21..724f6fbfa3 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -630,11 +630,6 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
if (!arrayData || !arrayData->length())
return;
- if (!comparefn.isUndefined() && !comparefn.isFunctionObject()) {
- engine->throwTypeError();
- return;
- }
-
// The spec says the sorting goes through a series of get,put and delete operations.
// this implies that the attributes don't get sorted around.
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index a32017210a..40a7123232 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -14,9 +14,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ArrayCtor);
-void Heap::ArrayCtor::init(QV4::ExecutionContext *scope)
+void Heap::ArrayCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Array"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Array"));
}
ReturnedValue ArrayCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -848,15 +848,69 @@ ReturnedValue ArrayPrototype::method_slice(const FunctionObject *b, const Value
ReturnedValue ArrayPrototype::method_sort(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
+ // Based on https://tc39.es/ecma262/#sec-array.prototype.sort
+
Scope scope(b);
+
+ ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
+
+ // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
+ if (!comparefn->isUndefined() && !comparefn->isFunctionObject())
+ return scope.engine->throwTypeError(QStringLiteral("The provided comparison function is not callable."));
+
+ // 2. Let obj be ? ToObject(this value).
ScopedObject instance(scope, thisObject->toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
+ // 3. Let len be ? LengthOfArrayLike(obj).
uint len = instance->getLength();
- ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
- ArrayData::sort(scope.engine, instance, comparefn, len);
+ if (instance->arrayData() && instance->arrayData()->length()) {
+ ArrayData::sort(scope.engine, instance, comparefn, len);
+ } else {
+ // Generic implementation that does not require a populated
+ // ArrayData, this is used, for example, by `Sequences` which
+ // store their data in a different way.
+
+ // 5. Let sortedList be ? SortIndexedProperties(obj, len, SortCompare, skip-holes)
+ Value* sorted = scope.alloc(scope.engine->safeForAllocLength(len));
+ CHECK_EXCEPTION();
+
+ uint written = 0;
+ for (uint index = 0; index < len; ++index) {
+ bool hasProperty = false;
+ auto element = instance->get(index, &hasProperty);
+
+ if (hasProperty) {
+ sorted[written] = element;
+ ++written;
+ }
+ }
+
+ std::stable_sort(sorted, sorted + written, ArrayElementLessThan(scope.engine, comparefn));
+
+ // [...]
+ // 8. Repeat, while j < itemCount,
+ // a. Perform ? Set(obj, ! ToString(𝔽(j)), sortedList[j], true).
+ // [...]
+ for (uint index = 0; index < written; ++index) {
+ instance->setIndexed(index, sorted[index], QV4::Object::DoThrowOnRejection);
+ CHECK_EXCEPTION();
+ }
+
+ // [...]
+ // 10. Repeat, while j < len,
+ // a. Perform ? DeletePropertyOrThrow(obj, ! ToString(𝔽(j))).
+ // [...]
+ while (written < len) {
+ if (!instance->deleteProperty(PropertyKey::fromArrayIndex(written)))
+ return scope.engine->throwTypeError();
+ ++written;
+ }
+ }
+
+ // 11. Return obj
return thisObject->asReturnedValue();
}
@@ -1490,4 +1544,3 @@ ReturnedValue ArrayPrototype::method_get_species(const FunctionObject *, const V
{
return thisObject->asReturnedValue();
}
-
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index b07e27b24f..a68068937f 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -50,7 +50,7 @@ namespace QV4 {
namespace Heap {
struct ArrayCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index 3110ec7992..5c1d50e753 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -8,9 +8,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(BooleanCtor);
DEFINE_OBJECT_VTABLE(BooleanObject);
-void Heap::BooleanCtor::init(QV4::ExecutionContext *scope)
+void Heap::BooleanCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Boolean"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Boolean"));
}
ReturnedValue BooleanCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index e009b0413a..1b2d3914ac 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -25,7 +25,7 @@ namespace QV4 {
namespace Heap {
struct BooleanCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 3ae3e5d24c..01f9b4adf3 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -32,7 +32,7 @@ Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int b
Heap::ExecutionContext *outer = static_cast<Heap::ExecutionContext *>(frame->context()->m());
c->outer.set(v4, outer);
if (frame->isJSTypesFrame()) {
- c->function.set(v4, static_cast<Heap::FunctionObject *>(
+ c->function.set(v4, static_cast<Heap::JavaScriptFunctionObject *>(
Value::fromStaticValue(
static_cast<JSTypesStackFrame *>(frame)->jsFrame->function).m()));
} else {
@@ -74,7 +74,7 @@ Heap::CallContext *ExecutionContext::newCallContext(JSTypesStackFrame *frame)
c->init();
c->outer.set(v4, outer);
- c->function.set(v4, static_cast<Heap::FunctionObject *>(
+ c->function.set(v4, static_cast<Heap::JavaScriptFunctionObject *>(
Value::fromStaticValue(frame->jsFrame->function).m()));
const CompiledData::Function *compiledFunction = function->compiledFunction;
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 82a9472223..48b6e04025 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -64,7 +64,7 @@ Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == 0);
Q_STATIC_ASSERT(offsetof(ExecutionContextData, activation) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE);
#define CallContextMembers(class, Member) \
- Member(class, Pointer, FunctionObject *, function) \
+ Member(class, Pointer, JavaScriptFunctionObject *, function) \
Member(class, ValueArray, ValueArray, locals)
DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) {
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index f4ca09a127..689eb9232b 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -13,9 +13,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(DataViewCtor);
DEFINE_OBJECT_VTABLE(DataView);
-void Heap::DataViewCtor::init(QV4::ExecutionContext *scope)
+void Heap::DataViewCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("DataView"));
+ Heap::FunctionObject::init(engine, QStringLiteral("DataView"));
}
static uint toIndex(ExecutionEngine *e, const Value &v)
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index ab2e1e589a..b5fa41d964 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -24,7 +24,7 @@ namespace QV4 {
namespace Heap {
struct DataViewCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
#define DataViewMembers(class, Member) \
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 6b64be3abb..2cb020e495 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -766,9 +766,9 @@ QDate DateObject::dateTimeToDate(const QDateTime &dateTime)
DEFINE_OBJECT_VTABLE(DateCtor);
-void Heap::DateCtor::init(QV4::ExecutionContext *scope)
+void Heap::DateCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Date"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Date"));
}
ReturnedValue DateCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index 7debcff4e9..4c184de897 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -189,7 +189,7 @@ private:
struct DateCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index a2a2e99a01..6754c3c887 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -627,25 +627,23 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this));
jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(ic->d()));
- ExecutionContext *global = rootContext();
-
- jsObjects[Object_Ctor] = memoryManager->allocate<ObjectCtor>(global);
- jsObjects[String_Ctor] = memoryManager->allocate<StringCtor>(global);
- jsObjects[Symbol_Ctor] = memoryManager->allocate<SymbolCtor>(global);
- jsObjects[Number_Ctor] = memoryManager->allocate<NumberCtor>(global);
- jsObjects[Boolean_Ctor] = memoryManager->allocate<BooleanCtor>(global);
- jsObjects[Array_Ctor] = memoryManager->allocate<ArrayCtor>(global);
- jsObjects[Function_Ctor] = memoryManager->allocate<FunctionCtor>(global);
- jsObjects[GeneratorFunction_Ctor] = memoryManager->allocate<GeneratorFunctionCtor>(global);
- jsObjects[Date_Ctor] = memoryManager->allocate<DateCtor>(global);
- jsObjects[RegExp_Ctor] = memoryManager->allocate<RegExpCtor>(global);
- jsObjects[Error_Ctor] = memoryManager->allocate<ErrorCtor>(global);
- jsObjects[EvalError_Ctor] = memoryManager->allocate<EvalErrorCtor>(global);
- jsObjects[RangeError_Ctor] = memoryManager->allocate<RangeErrorCtor>(global);
- jsObjects[ReferenceError_Ctor] = memoryManager->allocate<ReferenceErrorCtor>(global);
- jsObjects[SyntaxError_Ctor] = memoryManager->allocate<SyntaxErrorCtor>(global);
- jsObjects[TypeError_Ctor] = memoryManager->allocate<TypeErrorCtor>(global);
- jsObjects[URIError_Ctor] = memoryManager->allocate<URIErrorCtor>(global);
+ jsObjects[Object_Ctor] = memoryManager->allocate<ObjectCtor>(this);
+ jsObjects[String_Ctor] = memoryManager->allocate<StringCtor>(this);
+ jsObjects[Symbol_Ctor] = memoryManager->allocate<SymbolCtor>(this);
+ jsObjects[Number_Ctor] = memoryManager->allocate<NumberCtor>(this);
+ jsObjects[Boolean_Ctor] = memoryManager->allocate<BooleanCtor>(this);
+ jsObjects[Array_Ctor] = memoryManager->allocate<ArrayCtor>(this);
+ jsObjects[Function_Ctor] = memoryManager->allocate<FunctionCtor>(this);
+ jsObjects[GeneratorFunction_Ctor] = memoryManager->allocate<GeneratorFunctionCtor>(this);
+ jsObjects[Date_Ctor] = memoryManager->allocate<DateCtor>(this);
+ jsObjects[RegExp_Ctor] = memoryManager->allocate<RegExpCtor>(this);
+ jsObjects[Error_Ctor] = memoryManager->allocate<ErrorCtor>(this);
+ jsObjects[EvalError_Ctor] = memoryManager->allocate<EvalErrorCtor>(this);
+ jsObjects[RangeError_Ctor] = memoryManager->allocate<RangeErrorCtor>(this);
+ jsObjects[ReferenceError_Ctor] = memoryManager->allocate<ReferenceErrorCtor>(this);
+ jsObjects[SyntaxError_Ctor] = memoryManager->allocate<SyntaxErrorCtor>(this);
+ jsObjects[TypeError_Ctor] = memoryManager->allocate<TypeErrorCtor>(this);
+ jsObjects[URIError_Ctor] = memoryManager->allocate<URIErrorCtor>(this);
jsObjects[IteratorProto] = memoryManager->allocate<IteratorPrototype>();
ic = newInternalClass(ForInIteratorPrototype::staticVTable(), iteratorPrototype());
@@ -663,9 +661,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
// url
//
- jsObjects[Url_Ctor] = memoryManager->allocate<UrlCtor>(global);
+ jsObjects[Url_Ctor] = memoryManager->allocate<UrlCtor>(this);
jsObjects[UrlProto] = memoryManager->allocate<UrlPrototype>();
- jsObjects[UrlSearchParams_Ctor] = memoryManager->allocate<UrlSearchParamsCtor>(global);
+ jsObjects[UrlSearchParams_Ctor] = memoryManager->allocate<UrlSearchParamsCtor>(this);
jsObjects[UrlSearchParamsProto] = memoryManager->allocate<UrlSearchParamsPrototype>();
str = newString(QStringLiteral("get [Symbol.species]"));
@@ -703,19 +701,19 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
sequencePrototype()->cast<SequencePrototype>()->init();
- jsObjects[WeakMap_Ctor] = memoryManager->allocate<WeakMapCtor>(global);
+ jsObjects[WeakMap_Ctor] = memoryManager->allocate<WeakMapCtor>(this);
jsObjects[WeakMapProto] = memoryManager->allocate<WeakMapPrototype>();
static_cast<WeakMapPrototype *>(weakMapPrototype())->init(this, weakMapCtor());
- jsObjects[Map_Ctor] = memoryManager->allocate<MapCtor>(global);
+ jsObjects[Map_Ctor] = memoryManager->allocate<MapCtor>(this);
jsObjects[MapProto] = memoryManager->allocate<MapPrototype>();
static_cast<MapPrototype *>(mapPrototype())->init(this, mapCtor());
- jsObjects[WeakSet_Ctor] = memoryManager->allocate<WeakSetCtor>(global);
+ jsObjects[WeakSet_Ctor] = memoryManager->allocate<WeakSetCtor>(this);
jsObjects[WeakSetProto] = memoryManager->allocate<WeakSetPrototype>();
static_cast<WeakSetPrototype *>(weakSetPrototype())->init(this, weakSetCtor());
- jsObjects[Set_Ctor] = memoryManager->allocate<SetCtor>(global);
+ jsObjects[Set_Ctor] = memoryManager->allocate<SetCtor>(this);
jsObjects[SetProto] = memoryManager->allocate<SetPrototype>();
static_cast<SetPrototype *>(setPrototype())->init(this, setCtor());
@@ -723,33 +721,34 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
// promises
//
- jsObjects[Promise_Ctor] = memoryManager->allocate<PromiseCtor>(global);
+ jsObjects[Promise_Ctor] = memoryManager->allocate<PromiseCtor>(this);
jsObjects[PromiseProto] = memoryManager->allocate<PromisePrototype>();
static_cast<PromisePrototype *>(promisePrototype())->init(this, promiseCtor());
// typed arrays
- jsObjects[SharedArrayBuffer_Ctor] = memoryManager->allocate<SharedArrayBufferCtor>(global);
+ jsObjects[SharedArrayBuffer_Ctor] = memoryManager->allocate<SharedArrayBufferCtor>(this);
jsObjects[SharedArrayBufferProto] = memoryManager->allocate<SharedArrayBufferPrototype>();
static_cast<SharedArrayBufferPrototype *>(sharedArrayBufferPrototype())->init(this, sharedArrayBufferCtor());
- jsObjects[ArrayBuffer_Ctor] = memoryManager->allocate<ArrayBufferCtor>(global);
+ jsObjects[ArrayBuffer_Ctor] = memoryManager->allocate<ArrayBufferCtor>(this);
jsObjects[ArrayBufferProto] = memoryManager->allocate<ArrayBufferPrototype>();
static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor());
- jsObjects[DataView_Ctor] = memoryManager->allocate<DataViewCtor>(global);
+ jsObjects[DataView_Ctor] = memoryManager->allocate<DataViewCtor>(this);
jsObjects[DataViewProto] = memoryManager->allocate<DataViewPrototype>();
static_cast<DataViewPrototype *>(dataViewPrototype())->init(this, dataViewCtor());
jsObjects[ValueTypeProto] = (Heap::Base *) nullptr;
jsObjects[SignalHandlerProto] = (Heap::Base *) nullptr;
+ jsObjects[TypeWrapperProto] = (Heap::Base *) nullptr;
- jsObjects[IntrinsicTypedArray_Ctor] = memoryManager->allocate<IntrinsicTypedArrayCtor>(global);
+ jsObjects[IntrinsicTypedArray_Ctor] = memoryManager->allocate<IntrinsicTypedArrayCtor>(this);
jsObjects[IntrinsicTypedArrayProto] = memoryManager->allocate<IntrinsicTypedArrayPrototype>();
static_cast<IntrinsicTypedArrayPrototype *>(intrinsicTypedArrayPrototype())
->init(this, static_cast<IntrinsicTypedArrayCtor *>(intrinsicTypedArrayCtor()));
for (int i = 0; i < NTypedArrayTypes; ++i) {
- static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocate<TypedArrayCtor>(global, Heap::TypedArray::Type(i));
+ static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocate<TypedArrayCtor>(this, Heap::TypedArray::Type(i));
static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->allocate<TypedArrayPrototype>(Heap::TypedArray::Type(i));
typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].as<Object>()));
}
@@ -796,14 +795,14 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->allocate<MathObject>()));
globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->allocate<JsonObject>()));
globalObject->defineDefaultProperty(QStringLiteral("Reflect"), (o = memoryManager->allocate<Reflect>()));
- globalObject->defineDefaultProperty(QStringLiteral("Proxy"), (o = memoryManager->allocate<Proxy>(rootContext())));
+ globalObject->defineDefaultProperty(QStringLiteral("Proxy"), (o = memoryManager->allocate<Proxy>(this)));
globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Value::undefinedValue());
globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Value::fromDouble(std::numeric_limits<double>::quiet_NaN()));
globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Value::fromDouble(Q_INFINITY));
- jsObjects[Eval_Function] = memoryManager->allocate<EvalFunction>(global);
+ jsObjects[Eval_Function] = memoryManager->allocate<EvalFunction>(this);
globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction());
// ES6: 20.1.2.12 & 20.1.2.13:
@@ -832,7 +831,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
globalObject->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1);
globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1);
- ScopedFunctionObject t(scope, memoryManager->allocate<FunctionObject>(rootContext(), nullptr, ::throwTypeError));
+ ScopedFunctionObject t(
+ scope,
+ memoryManager->allocate<DynamicFunctionObject>(this, nullptr, ::throwTypeError));
t->defineReadonlyProperty(id_length(), Value::fromInt32(0));
t->setInternalClass(t->internalClass()->cryopreserved());
jsObjects[ThrowerObject] = t;
@@ -2478,18 +2479,22 @@ bool convertToIterable(QMetaType metaType, void *data, Source *sequence)
return false;
const QMetaType elementMetaType = iterable.valueMetaType();
- QVariant element(elementMetaType);
for (qsizetype i = 0, end = sequence->getLength(); i < end; ++i) {
- if (!ExecutionEngine::metaTypeFromJS(sequence->get(i), elementMetaType, element.data()))
- element = QVariant(elementMetaType);
+ QVariant element(elementMetaType);
+ ExecutionEngine::metaTypeFromJS(sequence->get(i), elementMetaType, element.data());
iterable.addValue(element, QSequentialIterable::AtEnd);
}
return true;
}
-// Converts a JS value to a meta-type.
-// data must point to a place that can store a value of the given type.
-// Returns true if conversion succeeded, false otherwise.
+/*!
+ * \internal
+ *
+ * Converts a JS value to a meta-type.
+ * \a data must point to a default-constructed instance of \a metaType.
+ * Returns \c true if conversion succeeded, \c false otherwise. In the latter case,
+ * \a data is not modified.
+ */
bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, void *data)
{
// check if it's one of the types we know
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 8e1bd24f6b..0958ab3ab5 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -217,6 +217,7 @@ public:
MapProto,
IntrinsicTypedArrayProto,
ValueTypeProto,
+ TypeWrapperProto,
SignalHandlerProto,
IteratorProto,
ForInIteratorProto,
@@ -342,6 +343,7 @@ public:
Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); }
Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); }
+ Object *typeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeWrapperProto); }
Object *iteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + IteratorProto); }
Object *forInIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ForInIteratorProto); }
Object *setIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetIteratorProto); }
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 35b5952d38..02145a0243 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -182,14 +182,14 @@ DEFINE_OBJECT_VTABLE(SyntaxErrorCtor);
DEFINE_OBJECT_VTABLE(TypeErrorCtor);
DEFINE_OBJECT_VTABLE(URIErrorCtor);
-void Heap::ErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::ErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Error"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Error"));
}
-void Heap::ErrorCtor::init(QV4::ExecutionContext *scope, const QString &name)
+void Heap::ErrorCtor::init(QV4::ExecutionEngine *engine, const QString &name)
{
- Heap::FunctionObject::init(scope, name);
+ Heap::FunctionObject::init(engine, name);
}
ReturnedValue ErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -203,9 +203,9 @@ ReturnedValue ErrorCtor::virtualCall(const FunctionObject *f, const Value *, con
return f->callAsConstructor(argv, argc);
}
-void Heap::EvalErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::EvalErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("EvalError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("EvalError"));
}
ReturnedValue EvalErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -214,9 +214,9 @@ ReturnedValue EvalErrorCtor::virtualCallAsConstructor(const FunctionObject *f, c
return ErrorObject::create<EvalErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::RangeErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::RangeErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("RangeError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("RangeError"));
}
ReturnedValue RangeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -225,9 +225,9 @@ ReturnedValue RangeErrorCtor::virtualCallAsConstructor(const FunctionObject *f,
return ErrorObject::create<RangeErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::ReferenceErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::ReferenceErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("ReferenceError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("ReferenceError"));
}
ReturnedValue ReferenceErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -236,9 +236,9 @@ ReturnedValue ReferenceErrorCtor::virtualCallAsConstructor(const FunctionObject
return ErrorObject::create<ReferenceErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::SyntaxErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::SyntaxErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("SyntaxError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("SyntaxError"));
}
ReturnedValue SyntaxErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -247,9 +247,9 @@ ReturnedValue SyntaxErrorCtor::virtualCallAsConstructor(const FunctionObject *f,
return ErrorObject::create<SyntaxErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::TypeErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::TypeErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("TypeError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("TypeError"));
}
ReturnedValue TypeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -258,9 +258,9 @@ ReturnedValue TypeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, c
return ErrorObject::create<TypeErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::URIErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::URIErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("URIError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("URIError"));
}
ReturnedValue URIErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 541f5cae36..f9adbb443b 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -79,32 +79,32 @@ struct URIErrorObject : ErrorObject {
};
struct ErrorCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
- void init(QV4::ExecutionContext *scope, const QString &name);
+ void init(ExecutionEngine *engine);
+ void init(ExecutionEngine *engine, const QString &name);
};
struct EvalErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct RangeErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct ReferenceErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct SyntaxErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct TypeErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct URIErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h
index 3f3335ef4e..930e138732 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit_p.h
+++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h
@@ -134,6 +134,7 @@ public:
bool ignoresFunctionSignature() const { return m_compilationUnit->ignoresFunctionSignature(); }
bool valueTypesAreCopied() const { return m_compilationUnit->valueTypesAreCopied(); }
bool valueTypesAreAddressable() const { return m_compilationUnit->valueTypesAreAddressable(); }
+ bool valueTypesAreAssertable() const { return m_compilationUnit->valueTypesAreAssertable(); }
bool componentsAreBound() const { return m_compilationUnit->componentsAreBound(); }
bool isESModule() const { return m_compilationUnit->isESModule(); }
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index ae36b563e0..82646e2822 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -1,20 +1,18 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qml/qqmlprivate.h"
#include "qv4function_p.h"
-#include "qv4managed_p.h"
-#include "qv4string_p.h"
-#include "qv4value_p.h"
-#include "qv4engine_p.h"
-#include <private/qv4mm_p.h>
-#include <private/qv4identifiertable_p.h>
+
+#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qqmltype_p_p.h>
+
+#include <private/qv4engine_p.h>
#include <private/qv4functiontable_p.h>
-#include <assembler/MacroAssemblerCodeRef.h>
-#include <private/qv4vme_moth_p.h>
-#include <private/qqmlglobal_p.h>
+#include <private/qv4identifiertable_p.h>
#include <private/qv4jscall_p.h>
-#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qv4vme_moth_p.h>
+
+#include <assembler/MacroAssemblerCodeRef.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index ab6a34435f..e9f91fbc06 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -30,84 +30,57 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(FunctionObject);
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name,
- VTable::Call call, VTable::CallWithMetaTypes callWithMetaTypes)
+void Heap::FunctionObject::init(QV4::ExecutionEngine *engine, QV4::String *name)
{
- jsCall = call;
- jsCallWithMetaTypes = callWithMetaTypes;
- jsConstruct = nullptr;
-
Object::init();
- this->scope.set(scope->engine(), scope->d());
- Scope s(scope->engine());
+ Scope s(engine);
ScopedFunctionObject f(s, this);
if (name)
f->setName(name);
}
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name)
+void Heap::FunctionObject::init(QV4::ExecutionEngine *engine, const QString &name)
{
- ExecutionEngine *e = scope->engine();
-
- jsCall = vtable()->call;
- jsCallWithMetaTypes = vtable()->callWithMetaTypes;
- jsConstruct = vtable()->callAsConstructor;
-
- Object::init();
- this->scope.set(scope->engine(), scope->d());
- Scope s(e);
- ScopedFunctionObject f(s, this);
- if (name)
- f->setName(name);
+ Scope valueScope(engine);
+ ScopedString s(valueScope, engine->newString(name));
+ init(engine, s);
}
-
-
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n)
-{
- jsCall = vtable()->call;
- jsCallWithMetaTypes = vtable()->callWithMetaTypes;
- jsConstruct = vtable()->callAsConstructor;
-
- Object::init();
- setFunction(function);
- this->scope.set(scope->engine(), scope->d());
- Scope s(scope->engine());
- ScopedString name(s, n ? n->d() : function->name());
- ScopedFunctionObject f(s, this);
- if (name)
- f->setName(name);
-}
-
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const QString &name)
+void Heap::FunctionObject::init()
{
- Scope valueScope(scope);
- ScopedString s(valueScope, valueScope.engine->newString(name));
- init(scope, s);
+ init(internalClass->engine, static_cast<QV4::String *>(nullptr));
}
-void Heap::FunctionObject::init()
+void Heap::JavaScriptFunctionObject::init(
+ QV4::ExecutionContext *scope, Function *function, QV4::String *n)
{
- jsCall = vtable()->call;
- jsCallWithMetaTypes = vtable()->callWithMetaTypes;
- jsConstruct = vtable()->callAsConstructor;
-
- Object::init();
- this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d());
+ Q_ASSERT(n || function);
+ Scope s(scope->engine());
+ ScopedString name(s, n ? n->d() : function->name());
+ FunctionObject::init(s.engine, name);
+ this->scope.set(s.engine, scope->d());
+ setFunction(function);
}
-void Heap::FunctionObject::setFunction(Function *f)
+void Heap::JavaScriptFunctionObject::setFunction(Function *f)
{
if (f) {
function = f;
function->executableCompilationUnit()->addref();
}
}
-void Heap::FunctionObject::destroy()
+void Heap::JavaScriptFunctionObject::destroy()
{
if (function)
function->executableCompilationUnit()->release();
- Object::destroy();
+ FunctionObject::destroy();
+}
+
+void Heap::DynamicFunctionObject::init(
+ QV4::ExecutionEngine *engine, QV4::String *name, VTable::Call call)
+{
+ FunctionObject::init(engine, name);
+ jsCall = call;
}
void FunctionObject::createDefaultPrototypeProperty(uint protoConstructorSlot)
@@ -121,32 +94,29 @@ void FunctionObject::createDefaultPrototypeProperty(uint protoConstructorSlot)
defineDefaultProperty(s.engine->id_prototype(), proto, Attr_NotEnumerable|Attr_NotConfigurable);
}
-void FunctionObject::call(QObject *thisObject, void **a, const QMetaType *types, int argc)
+ReturnedValue FunctionObject::name() const
{
- if (const auto callWithMetaTypes = d()->jsCallWithMetaTypes) {
- callWithMetaTypes(this, thisObject, a, types, argc);
- return;
- }
-
- QV4::convertAndCall(engine(), thisObject, a, types, argc,
- [this](const Value *thisObject, const Value *argv, int argc) {
- return call(thisObject, argv, argc);
- });
+ return get(engine()->id_name());
}
-ReturnedValue FunctionObject::name() const
+ReturnedValue FunctionObject::failCall() const
{
- return get(scope()->internalClass->engine->id_name());
+ return engine()->throwTypeError(QStringLiteral("Function can only be called with |new|."));
}
-ReturnedValue FunctionObject::virtualCall(const FunctionObject *, const Value *, const Value *, int)
+ReturnedValue FunctionObject::failCallAsConstructor() const
{
- return Encode::undefined();
+ return engine()->throwTypeError(QStringLiteral("Function is not a constructor."));
}
-void FunctionObject::virtualCallWithMetaTypes(
- const FunctionObject *, QObject *, void **, const QMetaType *, int)
+void FunctionObject::virtualConvertAndCall(
+ const FunctionObject *f, QObject *thisObject,
+ void **argv, const QMetaType *types, int argc)
{
+ QV4::convertAndCall(f->engine(), thisObject, argv, types, argc,
+ [f](const Value *thisObject, const Value *argv, int argc) {
+ return f->call(thisObject, argv, argc);
+ });
}
Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function)
@@ -156,15 +126,20 @@ Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *sco
return scope->engine()->memoryManager->allocate<ScriptFunction>(scope, function);
}
-Heap::FunctionObject *FunctionObject::createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor)
+Heap::FunctionObject *FunctionObject::createConstructorFunction(
+ ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor)
{
+ QV4::ExecutionEngine *engine = scope->engine();
if (!function) {
- Heap::DefaultClassConstructorFunction *c = scope->engine()->memoryManager->allocate<DefaultClassConstructorFunction>(scope);
+ Heap::DefaultClassConstructorFunction *c
+ = engine->memoryManager->allocate<DefaultClassConstructorFunction>(scope);
c->isDerivedConstructor = isDerivedConstructor;
return c;
}
- Heap::ConstructorFunction *c = scope->engine()->memoryManager->allocate<ConstructorFunction>(scope, function);
- c->homeObject.set(scope->engine(), homeObject->d());
+
+ Heap::ConstructorFunction *c
+ = engine->memoryManager->allocate<ConstructorFunction>(scope, function);
+ c->homeObject.set(engine, homeObject->d());
c->isDerivedConstructor = isDerivedConstructor;
return c;
}
@@ -183,7 +158,8 @@ Heap::FunctionObject *FunctionObject::createBuiltinFunction(ExecutionEngine *eng
if (!name)
name = engine->newString(QChar::fromLatin1('[') + QStringView{nameOrSymbol->toQString()}.mid(1) + QChar::fromLatin1(']'));
- ScopedFunctionObject function(scope, engine->memoryManager->allocate<FunctionObject>(engine->rootContext(), name, code));
+ ScopedFunctionObject function(
+ scope, engine->memoryManager->allocate<DynamicFunctionObject>(engine, name, code));
function->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(argumentCount));
return function->d();
}
@@ -199,16 +175,29 @@ ReturnedValue FunctionObject::getHomeObject() const
return Encode::undefined();
}
-QQmlSourceLocation FunctionObject::sourceLocation() const
+DEFINE_OBJECT_VTABLE(JavaScriptFunctionObject);
+
+QQmlSourceLocation JavaScriptFunctionObject::sourceLocation() const
{
return d()->function->sourceLocation();
}
+DEFINE_OBJECT_VTABLE(DynamicFunctionObject);
+
+ReturnedValue DynamicFunctionObject::virtualCall(
+ const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) {
+ Heap::DynamicFunctionObject *d = static_cast<const DynamicFunctionObject *>(f)->d();
+ if (d->jsCall)
+ return d->jsCall(f, thisObject, argv, argc);
+ return d->internalClass->engine->throwTypeError(
+ QStringLiteral("Function can only be called with |new|."));
+}
+
DEFINE_OBJECT_VTABLE(FunctionCtor);
-void Heap::FunctionCtor::init(QV4::ExecutionContext *scope)
+void Heap::FunctionCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Function"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Function"));
}
// 15.3.2
@@ -311,6 +300,12 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(engine->symbol_hasInstance(), method_hasInstance, 1, Attr_ReadOnly);
}
+ReturnedValue FunctionPrototype::virtualCall(
+ const FunctionObject *, const Value *, const Value *, int)
+{
+ return Encode::undefined();
+}
+
ReturnedValue FunctionPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
ExecutionEngine *v4 = b->engine();
@@ -427,10 +422,13 @@ ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Valu
boundArgs->set(scope.engine, i, argv[i + 1]);
}
- ScopedContext ctx(scope, target->scope());
- Scoped<BoundFunction> bound(scope, BoundFunction::create(ctx, target, boundThis, boundArgs));
- bound->d()->setFunction(target->function());
- return bound->asReturnedValue();
+ if (target->isConstructor()) {
+ return scope.engine->memoryManager->allocate<BoundConstructor>(target, boundThis, boundArgs)
+ ->asReturnedValue();
+ }
+
+ return scope.engine->memoryManager->allocate<BoundFunction>(target, boundThis, boundArgs)
+ ->asReturnedValue();
}
ReturnedValue FunctionPrototype::method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
@@ -490,7 +488,9 @@ DEFINE_OBJECT_VTABLE(ArrowFunction);
void ArrowFunction::virtualCallWithMetaTypes(const FunctionObject *fo, QObject *thisObject,
void **a, const QMetaType *types, int argc)
{
- if (fo->function()->kind != Function::AotCompiled) {
+ const ArrowFunction *self = static_cast<const ArrowFunction *>(fo);
+ Function *function = self->function();
+ if (function->kind != Function::AotCompiled) {
QV4::convertAndCall(fo->engine(), thisObject, a, types, argc,
[fo](const Value *thisObject, const Value *argv, int argc) {
return ArrowFunction::virtualCall(fo, thisObject, argv, argc);
@@ -499,16 +499,17 @@ void ArrowFunction::virtualCallWithMetaTypes(const FunctionObject *fo, QObject *
}
QV4::Scope scope(fo->engine());
- QV4::Scoped<ExecutionContext> context(scope, fo->scope());
+ QV4::Scoped<ExecutionContext> context(scope, self->scope());
MetaTypesStackFrame frame;
- frame.init(fo->function(), thisObject, context, a, types, argc);
+ frame.init(function, thisObject, context, a, types, argc);
frame.push(scope.engine);
Moth::VME::exec(&frame, scope.engine);
frame.pop(scope.engine);
}
-static ReturnedValue qfoDoCall(const QV4::FunctionObject *fo, const QV4::Value *thisObject,
- const QV4::Value *argv, int argc)
+static ReturnedValue qfoDoCall(
+ const QV4::JavaScriptFunctionObject *fo, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc)
{
ExecutionEngine *engine = fo->engine();
JSTypesStackFrame frame;
@@ -535,7 +536,8 @@ static ReturnedValue qfoDoCall(const QV4::FunctionObject *fo, const QV4::Value *
ReturnedValue ArrowFunction::virtualCall(const QV4::FunctionObject *fo, const Value *thisObject,
const QV4::Value *argv, int argc)
{
- Function *function = fo->function();
+ const ArrowFunction *self = static_cast<const ArrowFunction *>(fo);
+ Function *function = self->function();
switch (function->kind) {
case Function::AotCompiled:
return QV4::convertAndCall(
@@ -546,34 +548,24 @@ ReturnedValue ArrowFunction::virtualCall(const QV4::FunctionObject *fo, const Va
case Function::JsTyped:
return QV4::coerceAndCall(
fo->engine(), &function->jsTypedFunction, function->compiledFunction, argv, argc,
- [fo, thisObject](const Value *argv, int argc) {
- return qfoDoCall(fo, thisObject, argv, argc);
+ [self, thisObject](const Value *argv, int argc) {
+ return qfoDoCall(self, thisObject, argv, argc);
});
default:
break;
}
- return qfoDoCall(fo, thisObject, argv, argc);
+ return qfoDoCall(self, thisObject, argv, argc);
}
void Heap::ArrowFunction::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n)
{
- FunctionObject::init();
- this->scope.set(scope->engine(), scope->d());
-
- setFunction(function);
Q_ASSERT(function);
+ JavaScriptFunctionObject::init(scope, function, n);
Scope s(scope);
- ScopedFunctionObject f(s, this);
-
- ScopedString name(s, n ? n->d() : function->name());
- if (name)
- f->setName(name);
-
Q_ASSERT(internalClass && internalClass->verifyIndex(s.engine->id_length()->propertyKey(), Index_Length));
setProperty(s.engine, Index_Length, Value::fromInt32(int(function->compiledFunction->length)));
- canBeTailCalled = true;
}
void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function)
@@ -586,6 +578,13 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function
f->createDefaultPrototypeProperty(Heap::FunctionObject::Index_ProtoConstructor);
}
+void Heap::DefaultClassConstructorFunction::init(QV4::ExecutionContext *scope)
+{
+ Scope s(scope->engine());
+ FunctionObject::init(s.engine, nullptr);
+ this->scope.set(s.engine, scope->d());
+}
+
Heap::InternalClass *ScriptFunction::classForConstructor() const
{
Scope scope(engine());
@@ -613,8 +612,8 @@ ReturnedValue ConstructorFunction::virtualCallAsConstructor(const FunctionObject
ExecutionEngine *v4 = f->engine();
JSTypesStackFrame frame;
- frame.init(f->function(), argv, argc);
- frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
+ frame.init(c->function(), argv, argc);
+ frame.setupJSFrame(v4->jsStackTop, *f, c->scope(),
Value::emptyValue(),
newTarget ? *newTarget : Value::undefinedValue());
@@ -668,7 +667,7 @@ ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const Fu
JSTypesStackFrame frame;
frame.init(nullptr, argv, argc);
- frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
+ frame.setupJSFrame(v4->jsStackTop, *f, c->scope(),
Value::undefinedValue(),
newTarget ? *newTarget : Value::undefinedValue(), argc, argc);
@@ -705,33 +704,39 @@ DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
DEFINE_OBJECT_VTABLE(BoundFunction);
-void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject *target,
- const Value &boundThis, QV4::MemberData *boundArgs)
+void Heap::BoundFunction::init(
+ QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs)
{
- Scope s(scope);
- Heap::FunctionObject::init(scope, QStringLiteral("__bound function__"));
+ ExecutionEngine *engine = target->engine();
+ Scope s(engine);
+ ScopedString name(s, engine->newString(QStringLiteral("__bound function__")));
+ if (auto *js = target->as<QV4::JavaScriptFunctionObject>()) {
+ ScopedContext ctx(s, js->scope());
+ JavaScriptFunctionObject::init(ctx, js->function(), name);
+ } else {
+ Q_ASSERT(name);
+ JavaScriptFunctionObject::init(engine->rootContext(), nullptr, name);
+ }
+
this->target.set(s.engine, target->d());
this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : nullptr);
- this->boundThis.set(scope->engine(), boundThis);
-
- if (!target->isConstructor())
- jsConstruct = nullptr;
+ this->boundThis.set(s.engine, boundThis);
ScopedObject f(s, this);
- ScopedValue l(s, target->get(s.engine->id_length()));
+ ScopedValue l(s, target->get(engine->id_length()));
int len = l->toUInt32();
if (boundArgs)
len -= boundArgs->size();
if (len < 0)
len = 0;
- f->defineReadonlyConfigurableProperty(s.engine->id_length(), Value::fromInt32(len));
+ f->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(len));
ScopedProperty pd(s);
- pd->value = s.engine->thrower();
- pd->set = s.engine->thrower();
- f->insertMember(s.engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
- f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ pd->value = engine->thrower();
+ pd->set = engine->thrower();
+ f->insertMember(engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ f->insertMember(engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
}
ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *, const Value *argv, int argc)
@@ -755,7 +760,10 @@ ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *
return checkedResult(v4, target->call(jsCallData));
}
-ReturnedValue BoundFunction::virtualCallAsConstructor(const FunctionObject *fo, const Value *argv, int argc, const Value *)
+DEFINE_OBJECT_VTABLE(BoundConstructor);
+
+ReturnedValue BoundConstructor::virtualCallAsConstructor(
+ const FunctionObject *fo, const Value *argv, int argc, const Value *)
{
const BoundFunction *f = static_cast<const BoundFunction *>(fo);
Scope scope(f->engine());
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 573848f62a..f4a2935b5a 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -28,36 +28,41 @@ namespace QV4 {
struct IndexedBuiltinFunction;
struct JSCallData;
-namespace Heap {
-
+// A FunctionObject is generally something that can be called, either with a JavaScript
+// signature (QV4::Value etc) or with a C++ signature (QMetaType etc). For this, it has
+// the Call and CallWithMetaTypes VTable entries.
+// Some FunctionObjects need to select the actual implementation of the call at run time.
+// This comese in two flavors:
+// 1. The implementation is a JavaScript function. For these we have
+// JavaScriptFunctionObject that holds a QV4::Function member to defer the call to.
+// 2. The implementation is a C++ function. For these we have DynamicFunctionObject that
+// holds another Call member in the heap object to defer the call to.
+// In addition, a FunctionObject may want to be called as constructor. For this we have
+// another VTable entry and a flag in the heap object.
-#define FunctionObjectMembers(class, Member) \
- Member(class, Pointer, ExecutionContext *, scope) \
- Member(class, NoMark, Function *, function) \
- Member(class, NoMark, VTable::Call, jsCall) \
- Member(class, NoMark, VTable::CallAsConstructor, jsConstruct) \
- Member(class, NoMark, VTable::CallWithMetaTypes, jsCallWithMetaTypes) \
- Member(class, NoMark, bool, canBeTailCalled)
+namespace Heap {
+#define FunctionObjectMembers(class, Member)
DECLARE_HEAP_OBJECT(FunctionObject, Object) {
- DECLARE_MARKOBJECTS(FunctionObject)
enum {
Index_ProtoConstructor = 0,
Index_Prototype = 0,
Index_HasInstance = 1,
};
- bool isConstructor() const {
- return jsConstruct != nullptr;
- }
-
- Q_QML_EXPORT void init(
- QV4::ExecutionContext *scope, QV4::String *name,
- VTable::Call call, VTable::CallWithMetaTypes callWithMetaTypes = nullptr);
- Q_QML_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
- Q_QML_EXPORT void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
- Q_QML_EXPORT void init(QV4::ExecutionContext *scope, const QString &name);
+ Q_QML_EXPORT void init(QV4::ExecutionEngine *engine, QV4::String *name = nullptr);
+ Q_QML_EXPORT void init(QV4::ExecutionEngine *engine, const QString &name);
Q_QML_EXPORT void init();
+};
+
+#define JavaScriptFunctionObjectMembers(class, Member) \
+ Member(class, Pointer, ExecutionContext *, scope) \
+ Member(class, NoMark, Function *, function)
+
+DECLARE_HEAP_OBJECT(JavaScriptFunctionObject, FunctionObject) {
+ DECLARE_MARKOBJECTS(JavaScriptFunctionObject)
+
+ void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
Q_QML_EXPORT void destroy();
void setFunction(Function *f);
@@ -66,8 +71,18 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) {
unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; }
};
+#define DynamicFunctionObjectMembers(class, Member) \
+ Member(class, NoMark, VTable::Call, jsCall)
+
+DECLARE_HEAP_OBJECT(DynamicFunctionObject, FunctionObject) {
+ // NB: We might add a CallWithMetaTypes member to this struct and implement our
+ // builtins with metatypes, to be called from C++ code. This would make them
+ // available to qmlcachegen's C++ code generation.
+ void init(ExecutionEngine *engine, QV4::String *name, VTable::Call call);
+};
+
struct FunctionCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
struct FunctionPrototype : FunctionObject {
@@ -76,12 +91,12 @@ struct FunctionPrototype : FunctionObject {
// A function object with an additional index into a list.
// Used by Models to refer to property roles.
-struct IndexedBuiltinFunction : FunctionObject {
- inline void init(QV4::ExecutionContext *scope, qsizetype index, VTable::Call call);
+struct IndexedBuiltinFunction : DynamicFunctionObject {
+ inline void init(QV4::ExecutionEngine *engine, qsizetype index, VTable::Call call);
qsizetype index;
};
-struct ArrowFunction : FunctionObject {
+struct ArrowFunction : JavaScriptFunctionObject {
enum {
Index_Name = Index_HasInstance + 1,
Index_Length
@@ -116,9 +131,15 @@ DECLARE_HEAP_OBJECT(ConstructorFunction, ScriptFunction) {
bool isDerivedConstructor;
};
-struct DefaultClassConstructorFunction : FunctionObject
-{
+#define DefaultClassConstructorFunctionMembers(class, Member) \
+ Member(class, Pointer, ExecutionContext *, scope)
+
+DECLARE_HEAP_OBJECT(DefaultClassConstructorFunction, FunctionObject) {
+ DECLARE_MARKOBJECTS(DefaultClassConstructorFunction)
+
bool isDerivedConstructor;
+
+ void init(QV4::ExecutionContext *scope);
};
#define BoundFunctionMembers(class, Member) \
@@ -126,66 +147,72 @@ struct DefaultClassConstructorFunction : FunctionObject
Member(class, HeapValue, HeapValue, boundThis) \
Member(class, Pointer, MemberData *, boundArgs)
-DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) {
+DECLARE_HEAP_OBJECT(BoundFunction, JavaScriptFunctionObject) {
DECLARE_MARKOBJECTS(BoundFunction)
- void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs);
+ void init(QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs);
};
+struct BoundConstructor : BoundFunction {};
+
}
struct Q_QML_EXPORT FunctionObject: Object {
- enum {
- IsFunctionObject = true
- };
V4_OBJECT2(FunctionObject, Object)
Q_MANAGED_TYPE(FunctionObject)
V4_INTERNALCLASS(FunctionObject)
V4_PROTOTYPE(functionPrototype)
- V4_NEEDS_DESTROY
enum { NInlineProperties = 1 };
- bool canBeTailCalled() const { return d()->canBeTailCalled; }
- Heap::ExecutionContext *scope() const { return d()->scope; }
- Function *function() const { return d()->function; }
+ bool canBeTailCalled() const { return vtable()->isTailCallable; }
ReturnedValue name() const;
- unsigned int formalParameterCount() const { return d()->formalParameterCount(); }
- unsigned int varCount() const { return d()->varCount(); }
void setName(String *name) {
defineReadonlyConfigurableProperty(engine()->id_name(), *name);
}
void createDefaultPrototypeProperty(uint protoConstructorSlot);
- inline ReturnedValue callAsConstructor(const JSCallData &data) const;
- ReturnedValue callAsConstructor(const Value *argv, int argc, const Value *newTarget = nullptr) const {
- if (!d()->jsConstruct)
- return engine()->throwTypeError(QStringLiteral("Function is not a constructor."));
- return d()->jsConstruct(this, argv, argc, newTarget ? newTarget : this);
+ ReturnedValue callAsConstructor(
+ const Value *argv, int argc, const Value *newTarget = nullptr) const
+ {
+ if (const auto callAsConstructor = vtable()->callAsConstructor)
+ return callAsConstructor(this, argv, argc, newTarget ? newTarget : this);
+ return failCallAsConstructor();
}
- inline ReturnedValue call(const JSCallData &data) const;
- ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const {
- if (!d()->jsCall)
- return engine()->throwTypeError(QStringLiteral("Function can only be called with |new|."));
- return d()->jsCall(this, thisObject, argv, argc);
+
+ ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const
+ {
+ if (const auto call = vtable()->call)
+ return call(this, thisObject, argv, argc);
+ return failCall();
}
- static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
- void call(QObject *thisObject, void **a, const QMetaType *types, int argc);
- static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject,
- void **a, const QMetaType *types, int argc);
+
+ void call(QObject *thisObject, void **argv, const QMetaType *types, int argc) const
+ {
+ if (const auto callWithMetaTypes = vtable()->callWithMetaTypes)
+ callWithMetaTypes(this, thisObject, argv, types, argc);
+ else
+ failCall();
+ }
+
+ inline ReturnedValue callAsConstructor(const JSCallData &data) const;
+ inline ReturnedValue call(const JSCallData &data) const;
+
+ ReturnedValue failCall() const;
+ ReturnedValue failCallAsConstructor() const;
+ static void virtualConvertAndCall(
+ const FunctionObject *f, QObject *thisObject,
+ void **argv, const QMetaType *types, int argc);
static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function);
static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor);
static Heap::FunctionObject *createMemberFunction(ExecutionContext *scope, Function *function, Object *homeObject, String *name);
static Heap::FunctionObject *createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount);
- bool strictMode() const { return d()->function ? d()->function->isStrict() : false; }
bool isBinding() const;
bool isBoundFunction() const;
- bool isConstructor() const {
- return d()->isConstructor();
- }
+ bool isConstructor() const { return vtable()->callAsConstructor; }
ReturnedValue getHomeObject() const;
@@ -195,15 +222,40 @@ struct Q_QML_EXPORT FunctionObject: Object {
bool hasHasInstanceProperty() const {
return !internalClass()->propertyData.at(Heap::FunctionObject::Index_HasInstance).isEmpty();
}
-
- QQmlSourceLocation sourceLocation() const;
};
template<>
inline const FunctionObject *Value::as() const {
- return isManaged() && m()->internalClass->vtable->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : nullptr;
+ if (!isManaged())
+ return nullptr;
+
+ const VTable *vtable = m()->internalClass->vtable;
+ return (vtable->call || vtable->callAsConstructor)
+ ? reinterpret_cast<const FunctionObject *>(this)
+ : nullptr;
}
+struct Q_QML_EXPORT JavaScriptFunctionObject: FunctionObject
+{
+ V4_OBJECT2(JavaScriptFunctionObject, FunctionObject)
+ V4_NEEDS_DESTROY
+
+ Heap::ExecutionContext *scope() const { return d()->scope; }
+
+ Function *function() const { return d()->function; }
+ unsigned int formalParameterCount() const { return d()->formalParameterCount(); }
+ unsigned int varCount() const { return d()->varCount(); }
+ bool strictMode() const { return d()->function ? d()->function->isStrict() : false; }
+ QQmlSourceLocation sourceLocation() const;
+};
+
+struct Q_QML_EXPORT DynamicFunctionObject: FunctionObject
+{
+ V4_OBJECT2(DynamicFunctionObject, FunctionObject)
+
+ static ReturnedValue virtualCall(
+ const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
struct FunctionCtor: FunctionObject
{
@@ -225,6 +277,9 @@ struct FunctionPrototype: FunctionObject
void init(ExecutionEngine *engine, Object *ctor);
+ static ReturnedValue virtualCall(
+ const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+
static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_apply(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
@@ -232,23 +287,26 @@ struct FunctionPrototype: FunctionObject
static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
-struct Q_QML_EXPORT IndexedBuiltinFunction : FunctionObject
+struct Q_QML_EXPORT IndexedBuiltinFunction : DynamicFunctionObject
{
- V4_OBJECT2(IndexedBuiltinFunction, FunctionObject)
+ V4_OBJECT2(IndexedBuiltinFunction, DynamicFunctionObject)
};
void Heap::IndexedBuiltinFunction::init(
- QV4::ExecutionContext *scope, qsizetype index, VTable::Call call)
+ QV4::ExecutionEngine *engine, qsizetype index, VTable::Call call)
{
- Heap::FunctionObject::init(scope);
+ Heap::FunctionObject::init(engine);
this->jsCall = call;
this->index = index;
}
-struct ArrowFunction : FunctionObject {
- V4_OBJECT2(ArrowFunction, FunctionObject)
+struct ArrowFunction : JavaScriptFunctionObject {
+ V4_OBJECT2(ArrowFunction, JavaScriptFunctionObject)
V4_INTERNALCLASS(ArrowFunction)
- enum { NInlineProperties = 3 };
+ enum {
+ NInlineProperties = 3,
+ IsTailCallable = true,
+ };
static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject,
void **a, const QMetaType *types, int argc);
@@ -279,29 +337,33 @@ struct ConstructorFunction : ScriptFunction {
struct DefaultClassConstructorFunction : FunctionObject {
V4_OBJECT2(DefaultClassConstructorFunction, FunctionObject)
+
+ Heap::ExecutionContext *scope() const { return d()->scope; }
static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
-struct BoundFunction: FunctionObject {
- V4_OBJECT2(BoundFunction, FunctionObject)
-
- static Heap::BoundFunction *create(ExecutionContext *scope, FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs)
- {
- return scope->engine()->memoryManager->allocate<BoundFunction>(scope, target, boundThis, boundArgs);
- }
+struct BoundFunction: JavaScriptFunctionObject {
+ V4_OBJECT2(BoundFunction, JavaScriptFunctionObject)
Heap::FunctionObject *target() const { return d()->target; }
Value boundThis() const { return d()->boundThis; }
Heap::MemberData *boundArgs() const { return d()->boundArgs; }
- static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
+struct BoundConstructor: BoundFunction {
+ V4_OBJECT2(BoundConstructor, BoundFunction)
+
+ static ReturnedValue virtualCallAsConstructor(
+ const FunctionObject *f, const Value *argv, int argc, const Value *);
+};
+
inline bool FunctionObject::isBoundFunction() const
{
- return d()->vtable() == BoundFunction::staticVTable();
+ const VTable *vtable = d()->vtable();
+ return vtable == BoundFunction::staticVTable() || vtable == BoundConstructor::staticVTable();
}
inline ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result)
diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp
index e7a63ba185..f2d7dffde5 100644
--- a/src/qml/jsruntime/qv4generatorobject.cpp
+++ b/src/qml/jsruntime/qv4generatorobject.cpp
@@ -13,9 +13,9 @@ DEFINE_OBJECT_VTABLE(GeneratorFunctionCtor);
DEFINE_OBJECT_VTABLE(GeneratorFunction);
DEFINE_OBJECT_VTABLE(GeneratorObject);
-void Heap::GeneratorFunctionCtor::init(QV4::ExecutionContext *scope)
+void Heap::GeneratorFunctionCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("GeneratorFunction"));
+ Heap::FunctionObject::init(engine, QStringLiteral("GeneratorFunction"));
}
ReturnedValue GeneratorFunctionCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4generatorobject_p.h b/src/qml/jsruntime/qv4generatorobject_p.h
index 55ccc133aa..cb2c1962c5 100644
--- a/src/qml/jsruntime/qv4generatorobject_p.h
+++ b/src/qml/jsruntime/qv4generatorobject_p.h
@@ -33,7 +33,7 @@ enum class GeneratorState {
namespace Heap {
struct GeneratorFunctionCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct GeneratorFunction : ArrowFunction {
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index d15fb356c4..e3fc0ac1b3 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -80,6 +80,7 @@ namespace Heap {
struct ArrayObject;
struct DateObject;
struct FunctionObject;
+ struct JavaScriptFunctionObject;
struct ErrorObject;
struct ArgumentsObject;
struct QObjectWrapper;
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 37548ffc9f..989de0de23 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -290,10 +290,10 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok)
DEFINE_OBJECT_VTABLE(EvalFunction);
-void Heap::EvalFunction::init(QV4::ExecutionContext *scope)
+void Heap::EvalFunction::init(QV4::ExecutionEngine *engine)
{
- Scope s(scope);
- Heap::FunctionObject::init(scope, s.engine->id_eval());
+ Scope s(engine);
+ Heap::FunctionObject::init(engine, s.engine->id_eval());
ScopedFunctionObject f(s, this);
f->defineReadonlyConfigurableProperty(s.engine->id_length(), Value::fromInt32(1));
}
diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h
index 71e06ef417..fd23d71332 100644
--- a/src/qml/jsruntime/qv4globalobject_p.h
+++ b/src/qml/jsruntime/qv4globalobject_p.h
@@ -24,7 +24,7 @@ namespace QV4 {
namespace Heap {
struct EvalFunction : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h
index ed1ca983ad..43776e4b62 100644
--- a/src/qml/jsruntime/qv4jscall_p.h
+++ b/src/qml/jsruntime/qv4jscall_p.h
@@ -14,20 +14,17 @@
// We mean it.
//
-#include <private/qqmlengine_p.h>
#include <private/qqmllistwrapper_p.h>
-#include <private/qqmlvaluetype_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
+
#include <private/qv4alloca_p.h>
-#include <private/qv4context_p.h>
#include <private/qv4dateobject_p.h>
#include <private/qv4function_p.h>
#include <private/qv4functionobject_p.h>
-#include <private/qv4object_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4regexpobject_p.h>
#include <private/qv4scopedvalue_p.h>
-#include <private/qv4stackframe_p.h>
+#include <private/qv4sequenceobject_p.h>
#include <private/qv4urlobject_p.h>
#include <private/qv4variantobject_p.h>
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index c5f5fbff8e..aeac8c4914 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -77,7 +77,7 @@ struct Q_QML_EXPORT Managed : Value, VTableBase
IsString = false,
IsStringOrSymbol = false,
IsObject = false,
- IsFunctionObject = false,
+ IsTailCallable = false,
IsErrorObject = false,
IsArrayData = false
};
diff --git a/src/qml/jsruntime/qv4mapobject.cpp b/src/qml/jsruntime/qv4mapobject.cpp
index 4bb9617b93..5e7f92a339 100644
--- a/src/qml/jsruntime/qv4mapobject.cpp
+++ b/src/qml/jsruntime/qv4mapobject.cpp
@@ -12,14 +12,14 @@ DEFINE_OBJECT_VTABLE(WeakMapCtor);
DEFINE_OBJECT_VTABLE(MapCtor);
DEFINE_OBJECT_VTABLE(MapObject);
-void Heap::WeakMapCtor::init(QV4::ExecutionContext *scope)
+void Heap::WeakMapCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("WeakMap"));
+ Heap::FunctionObject::init(engine, QStringLiteral("WeakMap"));
}
-void Heap::MapCtor::init(QV4::ExecutionContext *scope)
+void Heap::MapCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Map"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Map"));
}
ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget, bool weakMap)
@@ -214,6 +214,17 @@ ReturnedValue WeakMapPrototype::method_set(const FunctionObject *b, const Value
(!argc || !argv[0].isObject()))
return scope.engine->throwTypeError();
+ QV4::WriteBarrier::markCustom(scope.engine, [&](QV4::MarkStack *ms) {
+ if (scope.engine->memoryManager->gcStateMachine->state <= GCState::FreeWeakMaps)
+ return;
+ Q_ASSERT(argv[0].heapObject());
+ argv[0].heapObject()->mark(ms);
+ if (argc > 1) {
+ if (auto *h = argv[1].heapObject())
+ h->mark(ms);
+ }
+ });
+
that->d()->esTable->set(argv[0], argc > 1 ? argv[1] : Value::undefinedValue());
return that.asReturnedValue();
}
@@ -317,6 +328,15 @@ ReturnedValue MapPrototype::method_set(const FunctionObject *b, const Value *thi
if (!that || that->d()->isWeakMap)
return scope.engine->throwTypeError();
+ QV4::WriteBarrier::markCustom(scope.engine, [&](QV4::MarkStack *ms) {
+ if (auto *h = argv[0].heapObject())
+ h->mark(ms);
+ if (argc > 1) {
+ if (auto *h = argv[1].heapObject())
+ h->mark(ms);
+ }
+ });
+
that->d()->esTable->set(argc ? argv[0] : Value::undefinedValue(), argc > 1 ? argv[1] : Value::undefinedValue());
return that.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4mapobject_p.h b/src/qml/jsruntime/qv4mapobject_p.h
index 68bc7ceed8..e7ff02c13a 100644
--- a/src/qml/jsruntime/qv4mapobject_p.h
+++ b/src/qml/jsruntime/qv4mapobject_p.h
@@ -27,11 +27,11 @@ class ESTable;
namespace Heap {
struct WeakMapCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct MapCtor : WeakMapCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct MapObject : Object {
@@ -78,7 +78,7 @@ struct WeakMapPrototype : Object
static ReturnedValue method_delete(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_has(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ Q_AUTOTEST_EXPORT static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
struct MapPrototype : WeakMapPrototype
@@ -92,7 +92,7 @@ struct MapPrototype : WeakMapPrototype
static ReturnedValue method_get(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_has(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_keys(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ Q_AUTOTEST_EXPORT static ReturnedValue method_set(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_get_size(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_values(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index d744e569f5..5299a2568a 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -36,9 +36,9 @@ const NumberLocale *NumberLocale::instance()
return numberLocaleHolder();
}
-void Heap::NumberCtor::init(QV4::ExecutionContext *scope)
+void Heap::NumberCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Number"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Number"));
}
ReturnedValue NumberCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index 8ac2bd1f79..3f0d6d9425 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -25,7 +25,7 @@ namespace QV4 {
namespace Heap {
struct NumberCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 1ad5e063e8..4c265a6b23 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -22,7 +22,7 @@
using namespace QV4;
using namespace Qt::Literals::StringLiterals;
-Q_LOGGING_CATEGORY(lcJavaScriptGlobals, "qt.qml.js.globals")
+Q_STATIC_LOGGING_CATEGORY(lcJavaScriptGlobals, "qt.qml.js.globals")
DEFINE_OBJECT_VTABLE(Object);
@@ -747,6 +747,12 @@ ReturnedValue Object::virtualResolveLookupGetter(const Object *object, Execution
Heap::Object *obj = object->d();
PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
+ if (object->as<QV4::ProxyObject>()) {
+ // proxies invalidate assumptions that we normally maek in lookups
+ // so we always need to use the fallback path
+ lookup->getter = Lookup::getterFallback;
+ return lookup->getter(lookup, engine, *object);
+ }
if (name.isArrayIndex()) {
lookup->indexedLookup.index = name.asArrayIndex();
lookup->getter = Lookup::getterIndexed;
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index e7f96a12ba..2a78bb4540 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -19,9 +19,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ObjectCtor);
-void Heap::ObjectCtor::init(QV4::ExecutionContext *scope)
+void Heap::ObjectCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Object"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Object"));
}
ReturnedValue ObjectCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index d152bfd175..d74cd64926 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -25,7 +25,7 @@ namespace QV4 {
namespace Heap {
struct ObjectCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
index 16cffea124..b8ede3e578 100644
--- a/src/qml/jsruntime/qv4promiseobject.cpp
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -314,9 +314,9 @@ void Heap::PromiseReaction::triggerWithValue(ExecutionEngine *e, const Value *va
handler->addReaction(e, reaction, value);
}
-void Heap::PromiseCtor::init(QV4::ExecutionContext *scope)
+void Heap::PromiseCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Promise"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Promise"));
}
void Heap::PromiseObject::init(ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4promiseobject_p.h b/src/qml/jsruntime/qv4promiseobject_p.h
index ca31f00881..fbde9f95e0 100644
--- a/src/qml/jsruntime/qv4promiseobject_p.h
+++ b/src/qml/jsruntime/qv4promiseobject_p.h
@@ -50,7 +50,7 @@ protected:
namespace Heap {
struct PromiseCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
#define PromiseObjectMembers(class, Member) \
diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp
index 109ab61059..974788d420 100644
--- a/src/qml/jsruntime/qv4proxy.cpp
+++ b/src/qml/jsruntime/qv4proxy.cpp
@@ -13,6 +13,7 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ProxyObject);
DEFINE_OBJECT_VTABLE(ProxyFunctionObject);
+DEFINE_OBJECT_VTABLE(ProxyConstructorObject);
void Heap::ProxyObject::init(const QV4::Object *target, const QV4::Object *handler)
{
@@ -25,12 +26,9 @@ void Heap::ProxyObject::init(const QV4::Object *target, const QV4::Object *handl
void Heap::ProxyFunctionObject::init(const QV4::FunctionObject *target, const QV4::Object *handler)
{
ExecutionEngine *e = internalClass->engine;
- FunctionObject::init(e->rootContext());
+ FunctionObject::init(e);
this->target.set(e, target->d());
this->handler.set(e, handler->d());
-
- if (!target->isConstructor())
- jsConstruct = nullptr;
}
@@ -643,7 +641,8 @@ OwnPropertyKeyIterator *ProxyObject::virtualOwnPropertyKeys(const Object *m, Val
}
-ReturnedValue ProxyFunctionObject::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
+ReturnedValue ProxyConstructorObject::virtualCallAsConstructor(
+ const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
{
Scope scope(f);
const ProxyObject *o = static_cast<const ProxyObject *>(f);
@@ -658,10 +657,8 @@ ReturnedValue ProxyFunctionObject::virtualCallAsConstructor(const FunctionObject
if (scope.hasException())
return Encode::undefined();
- if (trap->isNullOrUndefined()) {
- Q_ASSERT(target->isConstructor());
+ if (trap->isNullOrUndefined())
return target->callAsConstructor(argv, argc, newTarget);
- }
if (!trap->isFunctionObject())
return scope.engine->throwTypeError();
@@ -708,11 +705,11 @@ ReturnedValue ProxyFunctionObject::virtualCall(const FunctionObject *f, const Va
DEFINE_OBJECT_VTABLE(Proxy);
-void Heap::Proxy::init(QV4::ExecutionContext *ctx)
+void Heap::Proxy::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(ctx, QStringLiteral("Proxy"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Proxy"));
- Scope scope(ctx);
+ Scope scope(engine);
Scoped<QV4::Proxy> ctor(scope, this);
ctor->defineDefaultProperty(QStringLiteral("revocable"), QV4::Proxy::method_revocable, 2);
ctor->defineReadonlyConfigurableProperty(scope.engine->id_length(), Value::fromInt32(2));
@@ -734,9 +731,18 @@ ReturnedValue Proxy::virtualCallAsConstructor(const FunctionObject *f, const Val
return scope.engine->throwTypeError();
const FunctionObject *targetFunction = target->as<FunctionObject>();
- if (targetFunction)
- return scope.engine->memoryManager->allocate<ProxyFunctionObject>(targetFunction, handler)->asReturnedValue();
- return scope.engine->memoryManager->allocate<ProxyObject>(target, handler)->asReturnedValue();
+ if (!targetFunction) {
+ return scope.engine->memoryManager->allocate<ProxyObject>(target, handler)
+ ->asReturnedValue();
+ }
+
+ if (targetFunction->isConstructor()) {
+ return scope.engine->memoryManager->allocate<ProxyConstructorObject>(
+ targetFunction, handler)->asReturnedValue();
+ }
+
+ return scope.engine->memoryManager->allocate<ProxyFunctionObject>(targetFunction, handler)
+ ->asReturnedValue();
}
ReturnedValue Proxy::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
@@ -753,7 +759,10 @@ ReturnedValue Proxy::method_revocable(const FunctionObject *f, const Value *, co
Q_ASSERT(proxy);
ScopedString revoke(scope, scope.engine->newString(QStringLiteral("revoke")));
- ScopedFunctionObject revoker(scope, scope.engine->memoryManager->allocate<FunctionObject>(scope.engine->rootContext(), nullptr, method_revoke));
+ ScopedFunctionObject revoker(
+ scope,
+ scope.engine->memoryManager->allocate<DynamicFunctionObject>(
+ scope.engine, nullptr, method_revoke));
revoker->defineReadonlyConfigurableProperty(scope.engine->id_length(), Value::fromInt32(0));
revoker->defineDefaultProperty(scope.engine->symbol_revokableProxy(), proxy);
diff --git a/src/qml/jsruntime/qv4proxy_p.h b/src/qml/jsruntime/qv4proxy_p.h
index b3be05a11b..b3ce9c7a96 100644
--- a/src/qml/jsruntime/qv4proxy_p.h
+++ b/src/qml/jsruntime/qv4proxy_p.h
@@ -37,13 +37,15 @@ struct ProxyFunctionObject : ProxyObject {
void init(const QV4::FunctionObject *target, const QV4::Object *handler);
};
+struct ProxyConstructorObject : ProxyFunctionObject {};
+
#define ProxyMembers(class, Member) \
Member(class, Pointer, Symbol *, revokableProxySymbol) \
DECLARE_HEAP_OBJECT(Proxy, FunctionObject) {
DECLARE_MARKOBJECTS(Proxy)
- void init(QV4::ExecutionContext *ctx);
+ void init(ExecutionEngine *engine);
};
}
@@ -60,9 +62,6 @@ struct ProxyObject : FunctionObject {
V4_OBJECT2(ProxyObject, Object)
Q_MANAGED_TYPE(ProxyObject)
V4_INTERNALCLASS(ProxyObject)
- enum {
- IsFunctionObject = false
- };
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
@@ -81,14 +80,16 @@ struct ProxyFunctionObject : ProxyObject {
V4_OBJECT2(ProxyFunctionObject, FunctionObject)
Q_MANAGED_TYPE(ProxyObject)
V4_INTERNALCLASS(ProxyFunctionObject)
- enum {
- IsFunctionObject = true
- };
- static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *);
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
+struct ProxyConstructorObject : ProxyFunctionObject {
+ V4_OBJECT2(ProxyConstructorObject, ProxyFunctionObject)
+
+ static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *);
+};
+
struct Proxy : FunctionObject
{
V4_OBJECT2(Proxy, FunctionObject)
diff --git a/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp b/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp
index 13d93c7122..6521c98dbf 100644
--- a/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp
@@ -16,38 +16,15 @@ namespace QV4 {
void Heap::QMetaObjectWrapper::init(const QMetaObject *metaObject)
{
FunctionObject::init();
- this->metaObject = metaObject;
- constructors = nullptr;
- constructorCount = 0;
+ m_metaObject = metaObject;
}
void Heap::QMetaObjectWrapper::destroy()
{
- delete[] constructors;
+ delete[] m_constructors;
+ FunctionObject::destroy();
}
-void Heap::QMetaObjectWrapper::ensureConstructorsCache() {
-
- const int count = metaObject->constructorCount();
- if (constructorCount != count) {
- delete[] constructors;
- constructorCount = count;
- if (count == 0) {
- constructors = nullptr;
- return;
- }
- constructors = new QQmlPropertyData[count];
-
- for (int i = 0; i < count; ++i) {
- QMetaMethod method = metaObject->constructor(i);
- QQmlPropertyData &d = constructors[i];
- d.load(method);
- d.setCoreIndex(i);
- }
- }
-}
-
-
ReturnedValue QMetaObjectWrapper::create(ExecutionEngine *engine, const QMetaObject* metaObject) {
Scope scope(engine);
@@ -57,7 +34,7 @@ ReturnedValue QMetaObjectWrapper::create(ExecutionEngine *engine, const QMetaObj
}
void QMetaObjectWrapper::init(ExecutionEngine *) {
- const QMetaObject & mo = *d()->metaObject;
+ const QMetaObject &mo = *d()->metaObject();
for (int i = 0; i < mo.enumeratorCount(); i++) {
QMetaEnum Enum = mo.enumerator(i);
@@ -71,41 +48,49 @@ void QMetaObjectWrapper::init(ExecutionEngine *) {
ReturnedValue QMetaObjectWrapper::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *)
{
- const QMetaObjectWrapper *This = static_cast<const QMetaObjectWrapper*>(f);
- return This->constructInternal(argv, argc);
+ Q_ASSERT(f->as<QMetaObjectWrapper>());
+ return construct(static_cast<const QMetaObjectWrapper*>(f)->d(), argv, argc);
}
-ReturnedValue QMetaObjectWrapper::constructInternal(const Value *argv, int argc) const
+ReturnedValue QMetaObjectWrapper::constructInternal(
+ const QMetaObject *mo, const QQmlPropertyData *constructors, Heap::FunctionObject *d,
+ const Value *argv, int argc)
{
+ ExecutionEngine *v4 = d->internalClass->engine;
- d()->ensureConstructorsCache();
-
- ExecutionEngine *v4 = engine();
- const QMetaObject* mo = d()->metaObject;
- if (d()->constructorCount == 0) {
+ if (!constructors) {
return v4->throwTypeError(QLatin1String(mo->className())
+ QLatin1String(" has no invokable constructor"));
}
Scope scope(v4);
- Scoped<QObjectWrapper> object(scope);
+ ScopedObject object(scope);
JSCallData cData(nullptr, argv, argc);
CallData *callData = cData.callData(scope);
const QQmlObjectOrGadget objectOrGadget(mo);
- if (d()->constructorCount == 1) {
+ const auto callType = [](QMetaType metaType) {
+ return metaType.flags() & QMetaType::PointerToQObject
+ ? QMetaObject::CreateInstance
+ : QMetaObject::ConstructInPlace;
+ };
+
+ const int constructorCount = mo->constructorCount();
+ if (constructorCount == 1) {
object = QObjectMethod::callPrecise(
- objectOrGadget, d()->constructors[0], v4, callData, QMetaObject::CreateInstance);
+ objectOrGadget, constructors[0], v4, callData,
+ callType(constructors[0].propType()));
} else if (const QQmlPropertyData *ctor = QObjectMethod::resolveOverloaded(
- objectOrGadget, d()->constructors, d()->constructorCount, v4, callData)) {
+ objectOrGadget, constructors, constructorCount, v4, callData)) {
object = QObjectMethod::callPrecise(
- objectOrGadget, *ctor, v4, callData, QMetaObject::CreateInstance);
+ objectOrGadget, *ctor, v4, callData, callType(ctor->propType()));
}
+
if (object) {
- Scoped<QMetaObjectWrapper> metaObject(scope, this);
- object->defineDefaultProperty(v4->id_constructor(), metaObject);
- object->setPrototypeOf(const_cast<QMetaObjectWrapper*>(this));
+ Scoped<FunctionObject> functionObject(scope, d);
+ object->defineDefaultProperty(v4->id_constructor(), functionObject);
+ object->setPrototypeOf(functionObject);
}
return object.asReturnedValue();
diff --git a/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h b/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h
index 063bc089e7..c44b18f291 100644
--- a/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h
@@ -27,14 +27,57 @@ class QQmlPropertyData;
namespace QV4 {
namespace Heap {
-struct QMetaObjectWrapper : FunctionObject {
- const QMetaObject* metaObject;
- QQmlPropertyData *constructors;
- int constructorCount;
-
- void init(const QMetaObject* metaObject);
+struct QMetaObjectWrapper : FunctionObject
+{
+ void init(const QMetaObject *metaObject);
void destroy();
- void ensureConstructorsCache();
+
+ const QMetaObject *metaObject() const { return m_metaObject; }
+ QMetaType metaType() const
+ {
+ const QMetaType type = m_metaObject->metaType();
+ if (type.flags() & QMetaType::IsGadget)
+ return type;
+
+ // QObject* is our best guess because we can't get from a metatype to
+ // the metatype of its pointer.
+ return QMetaType::fromType<QObject *>();
+ }
+
+ const QQmlPropertyData *ensureConstructorsCache(
+ const QMetaObject *metaObject, QMetaType metaType)
+ {
+ Q_ASSERT(metaObject);
+ if (!m_constructors)
+ m_constructors = createConstructors(metaObject, metaType);
+ return m_constructors;
+ }
+
+
+ static const QQmlPropertyData *createConstructors(
+ const QMetaObject *metaObject, QMetaType metaType)
+ {
+ Q_ASSERT(metaObject);
+ const int count = metaObject->constructorCount();
+ if (count == 0)
+ return nullptr;
+
+ QQmlPropertyData *constructors = new QQmlPropertyData[count];
+
+ for (int i = 0; i < count; ++i) {
+ QMetaMethod method = metaObject->constructor(i);
+ QQmlPropertyData &d = constructors[i];
+ d.load(method);
+ d.setPropType(metaType);
+ d.setCoreIndex(i);
+ }
+
+ return constructors;
+ }
+
+private:
+ const QMetaObject *m_metaObject;
+ const QQmlPropertyData *m_constructors;
};
} // namespace Heap
@@ -45,7 +88,15 @@ struct Q_QML_EXPORT QMetaObjectWrapper : public FunctionObject
V4_NEEDS_DESTROY
static ReturnedValue create(ExecutionEngine *engine, const QMetaObject* metaObject);
- const QMetaObject *metaObject() const { return d()->metaObject; }
+ const QMetaObject *metaObject() const { return d()->metaObject(); }
+
+ template<typename HeapObject>
+ ReturnedValue static construct(HeapObject *d, const Value *argv, int argc)
+ {
+ const QMetaObject *mo = d->metaObject();
+ return constructInternal(
+ mo, d->ensureConstructorsCache(mo, d->metaType()), d, argv, argc);
+ }
protected:
static ReturnedValue virtualCallAsConstructor(
@@ -54,7 +105,10 @@ protected:
private:
void init(ExecutionEngine *engine);
- ReturnedValue constructInternal(const Value *argv, int argc) const;
+
+ static ReturnedValue constructInternal(
+ const QMetaObject *mo, const QQmlPropertyData *constructors, Heap::FunctionObject *d,
+ const Value *argv, int argc);
};
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index 53444cddb7..e1e882cb06 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -26,7 +26,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQmlContext, "qt.qml.context");
+Q_STATIC_LOGGING_CATEGORY(lcQmlContext, "qt.qml.context");
using namespace QV4;
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 5f85aae89e..b1d2b77a33 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -3,65 +3,57 @@
#include "qv4qobjectwrapper_p.h"
-#include <private/qqmlobjectorgadget_p.h>
-#include <private/qqmlengine_p.h>
-#include <private/qqmlvmemetaobject_p.h>
-#include <private/qqmlbinding_p.h>
#include <private/qjsvalue_p.h>
-#include <private/qqmlexpression_p.h>
-#include <private/qqmlglobal_p.h>
+
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlobjectorgadget_p.h>
+#include <private/qqmlpropertybinding_p.h>
+#include <private/qqmlscriptstring_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <private/qqmltypewrapper_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
-#include <private/qqmllistwrapper_p.h>
-#include <private/qqmlbuiltinfunctions_p.h>
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
-#endif
+#include <private/qqmlvmemetaobject_p.h>
#include <private/qv4arraybuffer_p.h>
+#include <private/qv4compileddata_p.h>
+#include <private/qv4dateobject_p.h>
#include <private/qv4functionobject_p.h>
-#include <private/qv4runtime_p.h>
-#include <private/qv4variantobject_p.h>
#include <private/qv4identifiertable_p.h>
-#include <private/qv4lookup_p.h>
-#include <private/qv4qmlcontext_p.h>
-#include <private/qv4sequenceobject_p.h>
-#include <private/qv4objectproto_p.h>
+#include <private/qv4jscall_p.h>
#include <private/qv4jsonobject_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4mm_p.h>
#include <private/qv4regexpobject_p.h>
-#include <private/qv4dateobject_p.h>
+#include <private/qv4runtime_p.h>
#include <private/qv4scopedvalue_p.h>
-#include <private/qv4jscall_p.h>
-#include <private/qv4mm_p.h>
-#include <private/qqmlscriptstring_p.h>
-#include <private/qv4compileddata_p.h>
-#include <private/qqmlpropertybinding_p.h>
-#include <private/qqmlpropertycachemethodarguments_p.h>
-#include <private/qqmlsignalnames_p.h>
+#include <private/qv4sequenceobject_p.h>
+#include <private/qv4variantobject_p.h>
-#include <QtQml/qjsvalue.h>
#include <QtCore/qjsonarray.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonvalue.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qatomic.h>
-#include <QtCore/qmetaobject.h>
-#if QT_CONFIG(qml_itemmodel)
-#include <QtCore/qabstractitemmodel.h>
-#endif
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qqueue.h>
+#include <QtCore/qtimer.h>
#include <QtCore/qtypes.h>
+#include <QtCore/qvarlengtharray.h>
#include <vector>
+
+#if QT_CONFIG(qml_itemmodel)
+#include <QtCore/qabstractitemmodel.h>
+#endif
+
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
-Q_LOGGING_CATEGORY(lcObjectConnect, "qt.qml.object.connect", QtWarningMsg)
-Q_LOGGING_CATEGORY(lcOverloadResolution, "qt.qml.overloadresolution", QtWarningMsg)
-Q_LOGGING_CATEGORY(lcMethodBehavior, "qt.qml.method.behavior")
-Q_LOGGING_CATEGORY(lcSignalHandler, "qt.qml.signalhandler")
+Q_LOGGING_CATEGORY(lcBuiltinsBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
+Q_STATIC_LOGGING_CATEGORY(lcObjectConnect, "qt.qml.object.connect", QtWarningMsg)
+Q_STATIC_LOGGING_CATEGORY(lcOverloadResolution, "qt.qml.overloadresolution", QtWarningMsg)
+Q_STATIC_LOGGING_CATEGORY(lcMethodBehavior, "qt.qml.method.behavior")
+Q_STATIC_LOGGING_CATEGORY(lcSignalHandler, "qt.qml.signalhandler")
// The code in this file does not violate strict aliasing, but GCC thinks it does
// so turn off the warnings for us to have a clean build
@@ -246,11 +238,8 @@ static ReturnedValue loadProperty(
property.readProperty(object, &v);
return QV4::JsonObject::fromJsonObject(v4, v);
}
- case QMetaType::QJsonArray: {
- QJsonArray v;
- property.readProperty(object, &v);
- return QV4::JsonObject::fromJsonArray(v4, v);
- }
+ case QMetaType::QJsonArray:
+ return encodeSequence(QMetaSequence::fromContainer<QJsonArray>());
case QMetaType::QStringList:
return encodeSequence(QMetaSequence::fromContainer<QStringList>());
case QMetaType::QVariantList:
@@ -360,20 +349,15 @@ ReturnedValue QObjectWrapper::getProperty(
Q_ASSERT(vmemo);
return vmemo->vmeMethod(property->coreIndex());
} else if (property->isV4Function()) {
- Scope scope(engine);
- ScopedContext global(scope, engine->qmlContext());
- if (!global)
- global = engine->rootContext();
return QObjectMethod::create(
- global, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
+ engine, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
} else if (property->isSignalHandler()) {
QmlSignalHandler::initProto(engine);
return engine->memoryManager->allocate<QmlSignalHandler>(
object, property->coreIndex())->asReturnedValue();
} else {
- ExecutionContext *global = engine->rootContext();
return QObjectMethod::create(
- global, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
+ engine, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
}
}
@@ -405,8 +389,7 @@ static OptionalReturnedValue getDestroyOrToStringMethod(
if (hasProperty)
*hasProperty = true;
- ExecutionContext *global = v4->rootContext();
- return OptionalReturnedValue(QObjectMethod::create(global, qobj, index));
+ return OptionalReturnedValue(QObjectMethod::create(v4, qobj, index));
}
static OptionalReturnedValue getPropertyFromImports(
@@ -608,7 +591,9 @@ void QObjectWrapper::setProperty(
Scope scope(engine);
if (ScopedFunctionObject f(scope, value); f) {
- if (!f->isBinding()) {
+ if (f->as<QQmlTypeWrapper>()) {
+ // Ignore. It's probably a singleton or an attached type.
+ } else if (!f->isBinding()) {
const bool isAliasToAllowed = [&]() {
if (property->isAlias()) {
const QQmlPropertyIndex originalIndex(property->coreIndex(), -1);
@@ -641,7 +626,7 @@ void QObjectWrapper::setProperty(
QQmlRefPointer<QQmlContextData> callingQmlContext = scope.engine->callingQmlContext();
Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
- ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
+ Scoped<JavaScriptFunctionObject> f(scope, bindingFunction->bindingFunction());
ScopedContext ctx(scope, f->scope());
// binding assignment.
@@ -679,13 +664,13 @@ void QObjectWrapper::setProperty(
}
}
- if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (Q_UNLIKELY(lcBuiltinsBindingRemoval().isInfoEnabled())) {
if (auto binding = QQmlPropertyPrivate::binding(object, QQmlPropertyIndex(property->coreIndex()))) {
const auto stackFrame = engine->currentStackFrame;
switch (binding->kind()) {
case QQmlAbstractBinding::QmlBinding: {
const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
- qCInfo(lcBindingRemoval,
+ qCInfo(lcBuiltinsBindingRemoval,
"Overwriting binding on %s::%s at %s:%d that was initially bound at %s",
object->metaObject()->className(), qPrintable(property->name(object)),
qPrintable(stackFrame->source()), stackFrame->lineNumber(),
@@ -694,7 +679,7 @@ void QObjectWrapper::setProperty(
}
case QQmlAbstractBinding::ValueTypeProxy:
case QQmlAbstractBinding::PropertyToPropertyBinding: {
- qCInfo(lcBindingRemoval,
+ qCInfo(lcBuiltinsBindingRemoval,
"Overwriting binding on %s::%s at %s:%d",
object->metaObject()->className(), qPrintable(property->name(object)),
qPrintable(stackFrame->source()), stackFrame->lineNumber());
@@ -722,7 +707,9 @@ void QObjectWrapper::setProperty(
const QMetaType propType = property->propType();
// functions are already handled, except for the QJSValue case
- Q_ASSERT(!value.as<FunctionObject>() || propType == QMetaType::fromType<QJSValue>());
+ Q_ASSERT(!value.as<FunctionObject>()
+ || value.as<QV4::QQmlTypeWrapper>()
+ || propType == QMetaType::fromType<QJSValue>());
if (value.isNull() && property->isQObject()) {
PROPERTY_STORE(QObject*, nullptr);
@@ -2559,21 +2546,22 @@ ReturnedValue CallArgument::toValue(ExecutionEngine *engine)
return Encode::undefined();
}
-ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::Object *wrapper, int index)
+ReturnedValue QObjectMethod::create(ExecutionEngine *engine, Heap::Object *wrapper, int index)
{
- Scope valueScope(scope);
+ Scope valueScope(engine);
Scoped<QObjectMethod> method(
valueScope,
- valueScope.engine->memoryManager->allocate<QObjectMethod>(scope, wrapper, index));
+ engine->memoryManager->allocate<QObjectMethod>(engine, wrapper, index));
return method.asReturnedValue();
}
-ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index)
+ReturnedValue QObjectMethod::create(
+ ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *valueType, int index)
{
- Scope valueScope(scope);
+ Scope valueScope(engine);
Scoped<QObjectMethod> method(
valueScope,
- valueScope.engine->memoryManager->allocate<QObjectMethod>(scope, valueType, index));
+ engine->memoryManager->allocate<QObjectMethod>(engine, valueType, index));
return method.asReturnedValue();
}
@@ -2596,11 +2584,10 @@ ReturnedValue QObjectMethod::create(
}
}
- Scoped<ExecutionContext> context(valueScope, cloneFrom->scope.get());
Scoped<QObjectMethod> method(
valueScope,
engine->memoryManager->allocate<QV4::QObjectMethod>(
- context, valueTypeWrapper ? valueTypeWrapper->d() : object, cloneFrom->index));
+ engine, valueTypeWrapper ? valueTypeWrapper->d() : object, cloneFrom->index));
method->d()->methodCount = cloneFrom->methodCount;
@@ -2626,10 +2613,10 @@ ReturnedValue QObjectMethod::create(
return method.asReturnedValue();
}
-void Heap::QObjectMethod::init(QV4::ExecutionContext *scope, Object *object, int methodIndex)
+void Heap::QObjectMethod::init(QV4::ExecutionEngine *engine, Object *object, int methodIndex)
{
- Heap::FunctionObject::init(scope);
- wrapper.set(internalClass->engine, object);
+ Heap::FunctionObject::init(engine);
+ wrapper.set(engine, object);
index = methodIndex;
}
@@ -3106,7 +3093,7 @@ ReturnedValue QmlSignalHandler::call(const Value *thisObject, const Value *argv,
Scope scope(engine());
Scoped<QObjectMethod> method(
scope, QObjectMethod::create(
- scope.engine->rootContext(),
+ scope.engine,
static_cast<Heap::QObjectWrapper *>(nullptr),
signalIndex()));
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 1af8fc887f..afd5b8ddc8 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -29,6 +29,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcBuiltinsBindingRemoval)
+
class QObject;
class QQmlData;
class QQmlPropertyCache;
@@ -72,7 +74,7 @@ DECLARE_EXPORTED_HEAP_OBJECT(QObjectMethod, FunctionObject) {
int methodCount;
int index;
- void init(QV4::ExecutionContext *scope, Object *wrapper, int index);
+ void init(QV4::ExecutionEngine *engine, Object *wrapper, int index);
void destroy()
{
if (methods != reinterpret_cast<const QQmlPropertyData *>(&_singleMethod))
@@ -348,10 +350,11 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
enum { DestroyMethod = -1, ToStringMethod = -2 };
- static ReturnedValue create(QV4::ExecutionContext *scope, Heap::Object *wrapper, int index);
+ static ReturnedValue create(ExecutionEngine *engine, Heap::Object *wrapper, int index);
+ static ReturnedValue create(
+ ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *valueType, int index);
static ReturnedValue create(
- QV4::ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index);
- static ReturnedValue create(QV4::ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
+ ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
Heap::Object *wrapper, Heap::Object *object);
int methodIndex() const { return d()->index; }
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index acb9f0acfc..144cd39bcd 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -195,9 +195,9 @@ ReturnedValue RegExpObject::builtinExec(ExecutionEngine *engine, const String *s
DEFINE_OBJECT_VTABLE(RegExpCtor);
-void Heap::RegExpCtor::init(QV4::ExecutionContext *scope)
+void Heap::RegExpCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("RegExp"));
+ Heap::FunctionObject::init(engine, QStringLiteral("RegExp"));
clearLastMatch();
}
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 8d52300013..179a01fb45 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -50,7 +50,7 @@ DECLARE_HEAP_OBJECT(RegExpObject, Object) {
DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) {
DECLARE_MARKOBJECTS(RegExpCtor)
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
void clearLastMatch();
};
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index c51c94ffe4..b5c497be49 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -41,6 +41,8 @@
QT_BEGIN_NAMESPACE
+Q_STATIC_LOGGING_CATEGORY(lcCoercingTypeAssertion, "qt.qml.coercingTypeAssertion");
+
namespace QV4 {
#ifdef QV4_COUNT_RUNTIME_FUNCTIONS
@@ -380,11 +382,42 @@ QV4::ReturnedValue Runtime::As::call(ExecutionEngine *engine, const Value &lval,
else if (result->isBoolean())
return Encode::null();
+ if (engine->callingQmlContext()->valueTypesAreAssertable())
+ return Encode::undefined();
+
// Try to convert the value type
- if (Scoped<QQmlTypeWrapper> typeWrapper(scope, rval); typeWrapper)
- return coerce(engine, lval, typeWrapper->d()->type(), false);
+ Scoped<QQmlTypeWrapper> typeWrapper(scope, rval);
+ if (!typeWrapper)
+ return Encode::undefined();
- return Encode::undefined();
+ const auto *stackFrame = engine->currentStackFrame;
+ if (lval.as<QQmlValueTypeWrapper>()) {
+ qCWarning(lcCoercingTypeAssertion).nospace().noquote()
+ << stackFrame->source() << ':' << stackFrame->lineNumber() << ':'
+ << " Coercing between incompatible value types mistakenly yields null rather than"
+ << " undefined. Add 'pragma ValueTypeBehavior: Assertable' to prevent this.";
+ return Encode::null();
+ }
+
+ if (lval.as<QV4::QObjectWrapper>()) {
+ qCWarning(lcCoercingTypeAssertion).nospace().noquote()
+ << stackFrame->source() << ':' << stackFrame->lineNumber() << ':'
+ << " Coercing from instances of object types to value types mistakenly yields null"
+ << " rather than undefined. Add 'pragma ValueTypeBehavior: Assertable' to prevent"
+ << " this.";
+ return Encode::null();
+ }
+
+ result = coerce(engine, lval, typeWrapper->d()->type(), false);
+ if (result->isUndefined())
+ return Encode::undefined();
+
+ qCWarning(lcCoercingTypeAssertion).nospace().noquote()
+ << stackFrame->source() << ':' << stackFrame->lineNumber() << ':'
+ << " Coercing a value to " << typeWrapper->toQStringNoThrow()
+ << " using a type assertion. This behavior is deprecated."
+ << " Add 'pragma ValueTypeBehavior: Assertable' to prevent it.";
+ return result->asReturnedValue();
}
QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left, const Value &right)
@@ -1029,7 +1062,7 @@ ReturnedValue Runtime::LoadName::call(ExecutionEngine *engine, int nameIndex)
static Object *getSuperBase(Scope &scope)
{
- ScopedFunctionObject f(scope);
+ Scoped<JavaScriptFunctionObject> f(scope);
ScopedObject homeObject(scope);
if (scope.engine->currentStackFrame->isJSTypesFrame()) {
JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(
@@ -1188,7 +1221,7 @@ ReturnedValue Runtime::LoadSuperConstructor::call(ExecutionEngine *engine, const
if (!f)
return engine->throwTypeError();
Heap::Object *c = static_cast<const Object &>(t).getPrototypeOf();
- if (!c->vtable()->isFunctionObject || !static_cast<Heap::FunctionObject *>(c)->isConstructor())
+ if (!c->vtable()->callAsConstructor)
return engine->throwTypeError();
return c->asReturnedValue();
}
@@ -1627,20 +1660,23 @@ ReturnedValue Runtime::TailCall::call(JSTypesStackFrame *frame, ExecutionEngine
int argc = tos[StackOffsets::tailCall_argc].int_32();
Q_ASSERT(argc >= 0);
- if (!function.isFunctionObject())
+ const JavaScriptFunctionObject *jsfo = function.as<JavaScriptFunctionObject>();
+ if (!jsfo) {
+ if (const FunctionObject *fo = function.as<FunctionObject>())
+ return checkedResult(engine, fo->call(&thisObject, argv, argc));
return engine->throwTypeError();
+ }
- const FunctionObject &fo = static_cast<const FunctionObject &>(function);
- if (!frame->callerCanHandleTailCall() || !fo.canBeTailCalled() || engine->debugger()
- || unsigned(argc) > fo.formalParameterCount()) {
+ if (!frame->callerCanHandleTailCall() || !jsfo->canBeTailCalled() || engine->debugger()
+ || unsigned(argc) > jsfo->formalParameterCount()) {
// Cannot tailcall, do a normal call:
- return checkedResult(engine, fo.call(&thisObject, argv, argc));
+ return checkedResult(engine, jsfo->call(&thisObject, argv, argc));
}
memmove(frame->jsFrame->args, argv, argc * sizeof(Value));
- frame->init(fo.function(), frame->jsFrame->argValues<Value>(), argc,
+ frame->init(jsfo->function(), frame->jsFrame->argValues<Value>(), argc,
frame->callerCanHandleTailCall());
- frame->setupJSFrame(frame->framePointer(), fo, fo.scope(), thisObject,
+ frame->setupJSFrame(frame->framePointer(), *jsfo, jsfo->scope(), thisObject,
Primitive::undefinedValue());
engine->jsStackTop = frame->framePointer() + frame->requiredJSStackFrameSize();
frame->setPendingTailCall(true);
@@ -1771,6 +1807,21 @@ void Runtime::ThrowOnNullOrUndefined::call(ExecutionEngine *engine, const Value
engine->throwTypeError();
}
+void Runtime::MarkCustom::call(const Value &toBeMarked)
+{
+ auto *h = toBeMarked.heapObject();
+ if (!h)
+ return;
+ Q_ASSERT(h->internalClass);
+ auto engine = h->internalClass->engine;
+ Q_ASSERT(engine);
+ // runtime function is only meant to be called while gc is ongoing
+ Q_ASSERT(engine->isGCOngoing);
+ QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *ms) {
+ h->mark(ms);
+ });
+}
+
ReturnedValue Runtime::ConvertThisToObject::call(ExecutionEngine *engine, const Value &t)
{
if (!t.isObject()) {
@@ -2457,6 +2508,8 @@ QHash<const void *, const char *> Runtime::symbolTable()
{symbol<Closure>(), "Closure" },
+ {symbol<MarkCustom>(), "MarkCustom"},
+
{symbol<ConvertThisToObject>(), "ConvertThisToObject" },
{symbol<DeclareVar>(), "DeclareVar" },
{symbol<CreateMappedArgumentsObject>(), "CreateMappedArgumentsObject" },
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index fdee6ac580..e4a8c09370 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -230,6 +230,12 @@ struct Q_QML_EXPORT Runtime {
static void call(ExecutionEngine *, const Value &);
};
+ /* garbage collection */
+ struct Q_QML_EXPORT MarkCustom : PureMethod
+ {
+ static void call(const Value &toBeMarked);
+ };
+
/* closures */
struct Q_QML_EXPORT Closure : Method<Throws::No>
{
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index cc899428c2..8de85a86bf 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -42,25 +42,6 @@ static ReturnedValue doGetIndexed(const Sequence *s, qsizetype index) {
return v->asReturnedValue();
}
-template<typename Compare>
-void sortSequence(Sequence *sequence, const Compare &compare)
-{
- /* non-const */ Heap::Sequence *p = sequence->d();
-
- QSequentialIterable iterable(p->metaSequence(), p->listType(), p->storagePointer());
- if (iterable.canRandomAccessIterate()) {
- std::sort(QSequentialIterable::RandomAccessIterator(iterable.mutableBegin()),
- QSequentialIterable::RandomAccessIterator(iterable.mutableEnd()),
- compare);
- } else if (iterable.canReverseIterate()) {
- std::sort(QSequentialIterable::BidirectionalIterator(iterable.mutableBegin()),
- QSequentialIterable::BidirectionalIterator(iterable.mutableEnd()),
- compare);
- } else {
- qWarning() << "Container has no suitable iterator for sorting";
- }
-}
-
// helper function to generate valid warnings if errors occur during sequence operations.
static void generateWarning(QV4::ExecutionEngine *v4, const QString& description)
{
@@ -108,40 +89,6 @@ struct SequenceOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
}
};
-struct SequenceCompareFunctor
-{
- SequenceCompareFunctor(QV4::ExecutionEngine *v4, const QV4::Value &compareFn)
- : m_v4(v4), m_compareFn(&compareFn)
- {}
-
- bool operator()(const QVariant &lhs, const QVariant &rhs)
- {
- QV4::Scope scope(m_v4);
- ScopedFunctionObject compare(scope, m_compareFn);
- if (!compare)
- return m_v4->throwTypeError();
- Value *argv = scope.alloc(2);
- argv[0] = m_v4->fromVariant(lhs);
- argv[1] = m_v4->fromVariant(rhs);
- QV4::ScopedValue result(scope, compare->call(m_v4->globalObject, argv, 2));
- if (scope.hasException())
- return false;
- return result->toNumber() < 0;
- }
-
-private:
- QV4::ExecutionEngine *m_v4;
- const QV4::Value *m_compareFn;
-};
-
-struct SequenceDefaultCompareFunctor
-{
- bool operator()(const QVariant &lhs, const QVariant &rhs)
- {
- return lhs.toString() < rhs.toString();
- }
-};
-
void Heap::Sequence::initTypes(QMetaType listType, QMetaSequence metaSequence)
{
m_listType = listType.iface();
@@ -250,6 +197,42 @@ QVariant Sequence::at(qsizetype index) const
return result;
}
+QVariant Sequence::shift()
+{
+ auto *p = d();
+ void *storage = p->storagePointer();
+ Q_ASSERT(storage); // Must readReference() before
+ const QMetaType v = p->valueMetaType();
+ const QMetaSequence m = p->metaSequence();
+
+ const auto variantData = [&](QVariant *variant) -> void *{
+ if (v == QMetaType::fromType<QVariant>())
+ return variant;
+
+ *variant = QVariant(v);
+ return variant->data();
+ };
+
+ QVariant result;
+ void *resultData = variantData(&result);
+ m.valueAtIndex(storage, 0, resultData);
+
+ if (m.canRemoveValueAtBegin()) {
+ m.removeValueAtBegin(storage);
+ return result;
+ }
+
+ QVariant t;
+ void *tData = variantData(&t);
+ for (qsizetype i = 1, end = m.size(storage); i < end; ++i) {
+ m.valueAtIndex(storage, i, tData);
+ m.setValueAtIndex(storage, i - 1, tData);
+ }
+ m.removeValueAtEnd(storage);
+
+ return result;
+}
+
template<typename Action>
void convertAndDo(const QVariant &item, const QMetaType v, Action action)
@@ -404,24 +387,6 @@ bool Sequence::containerIsEqualTo(Managed *other)
return false;
}
-bool Sequence::sort(const FunctionObject *f, const Value *, const Value *argv, int argc)
-{
- if (d()->isReadOnly())
- return false;
- if (d()->isReference() && !loadReference())
- return false;
-
- if (argc == 1 && argv[0].as<FunctionObject>())
- sortSequence(this, SequenceCompareFunctor(f->engine(), argv[0]));
- else
- sortSequence(this, SequenceDefaultCompareFunctor());
-
- if (d()->object())
- storeReference();
-
- return true;
-}
-
void *Sequence::getRawContainerPtr() const
{ return d()->storagePointer(); }
@@ -599,9 +564,9 @@ static QV4::ReturnedValue method_set_length(const FunctionObject *f, const Value
void SequencePrototype::init()
{
- defineDefaultProperty(QStringLiteral("sort"), method_sort, 1);
defineDefaultProperty(engine()->id_valueOf(), method_valueOf, 0);
defineAccessorProperty(QStringLiteral("length"), method_get_length, method_set_length);
+ defineDefaultProperty(QStringLiteral("shift"), method_shift, 0);
}
ReturnedValue SequencePrototype::method_valueOf(const FunctionObject *f, const Value *thisObject, const Value *, int)
@@ -609,22 +574,27 @@ ReturnedValue SequencePrototype::method_valueOf(const FunctionObject *f, const V
return Encode(thisObject->toString(f->engine()));
}
-ReturnedValue SequencePrototype::method_sort(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue SequencePrototype::method_shift(
+ const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
Scope scope(b);
- QV4::ScopedObject o(scope, thisObject);
- if (!o || !o->isV4SequenceType())
- THROW_TYPE_ERROR();
+ Scoped<Sequence> s(scope, thisObject);
+ if (!s)
+ return ArrayPrototype::method_shift(b, thisObject, argv, argc);
- if (argc >= 2)
- return o.asReturnedValue();
+ if (s->d()->isReference() && !s->loadReference())
+ RETURN_UNDEFINED();
- if (auto *s = o->as<Sequence>()) {
- if (!s->sort(b, thisObject, argv, argc))
- THROW_TYPE_ERROR();
- }
+ const qsizetype len = s->size();
+ if (!len)
+ RETURN_UNDEFINED();
+
+ ScopedValue result(scope, scope.engine->fromVariant(s->shift()));
+
+ if (s->d()->object())
+ s->storeReference();
- return o.asReturnedValue();
+ return result->asReturnedValue();
}
ReturnedValue SequencePrototype::newSequence(
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 3d1baf6c77..0908e52574 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -34,7 +34,7 @@ struct Q_QML_EXPORT SequencePrototype : public QV4::Object
void init();
static ReturnedValue method_valueOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
- static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_shift(const FunctionObject *b, const Value *thisObject, const Value *, int);
static ReturnedValue newSequence(
QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data,
@@ -101,6 +101,7 @@ public:
qsizetype size() const;
QVariant at(qsizetype index) const;
+ QVariant shift();
void append(const QVariant &item);
void append(qsizetype num, const QVariant &item);
void replace(qsizetype index, const QVariant &item);
@@ -110,7 +111,6 @@ public:
bool containerPutIndexed(qsizetype index, const QV4::Value &value);
bool containerDeleteIndexedProperty(qsizetype index);
bool containerIsEqualTo(Managed *other);
- bool sort(const FunctionObject *f, const Value *, const Value *argv, int argc);
void *getRawContainerPtr() const;
bool loadReference() const;
bool storeReference();
diff --git a/src/qml/jsruntime/qv4setobject.cpp b/src/qml/jsruntime/qv4setobject.cpp
index a7589a40db..43cf34d2c3 100644
--- a/src/qml/jsruntime/qv4setobject.cpp
+++ b/src/qml/jsruntime/qv4setobject.cpp
@@ -14,14 +14,14 @@ DEFINE_OBJECT_VTABLE(SetCtor);
DEFINE_OBJECT_VTABLE(WeakSetCtor);
DEFINE_OBJECT_VTABLE(SetObject);
-void Heap::WeakSetCtor::init(QV4::ExecutionContext *scope)
+void Heap::WeakSetCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("WeakSet"));
+ Heap::FunctionObject::init(engine, QStringLiteral("WeakSet"));
}
-void Heap::SetCtor::init(QV4::ExecutionContext *scope)
+void Heap::SetCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Set"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Set"));
}
ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget, bool isWeak)
@@ -104,6 +104,12 @@ ReturnedValue WeakSetPrototype::method_add(const FunctionObject *b, const Value
(!argc || !argv[0].isObject()))
return scope.engine->throwTypeError();
+ QV4::WriteBarrier::markCustom(scope.engine, [&](QV4::MarkStack *ms) {
+ if (scope.engine->memoryManager->gcStateMachine->state <= GCState::FreeWeakSets)
+ return;
+ argv[0].heapObject()->mark(ms);
+ });
+
that->d()->esTable->set(argv[0], Value::undefinedValue());
return that.asReturnedValue();
}
@@ -192,6 +198,11 @@ ReturnedValue SetPrototype::method_add(const FunctionObject *b, const Value *thi
if (!that || that->d()->isWeakSet)
return scope.engine->throwTypeError();
+ QV4::WriteBarrier::markCustom(scope.engine, [&](QV4::MarkStack *ms) {
+ if (auto *h = argv[0].heapObject())
+ h->mark(ms);
+ });
+
that->d()->esTable->set(argv[0], Value::undefinedValue());
return that.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4setobject_p.h b/src/qml/jsruntime/qv4setobject_p.h
index 6ed44b4ed9..118cdebd5a 100644
--- a/src/qml/jsruntime/qv4setobject_p.h
+++ b/src/qml/jsruntime/qv4setobject_p.h
@@ -29,12 +29,12 @@ class ESTable;
namespace Heap {
struct WeakSetCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct SetCtor : WeakSetCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct SetObject : Object {
@@ -79,7 +79,7 @@ struct WeakSetPrototype : Object
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_add(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ Q_AUTOTEST_EXPORT static ReturnedValue method_add(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_delete(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_has(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
@@ -89,7 +89,7 @@ struct SetPrototype : WeakSetPrototype
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_add(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ Q_AUTOTEST_EXPORT static ReturnedValue method_add(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_clear(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_delete(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_entries(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index ad3c39c7b9..5f3d833f33 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -131,9 +131,9 @@ PropertyAttributes StringObject::virtualGetOwnProperty(const Managed *m, Propert
DEFINE_OBJECT_VTABLE(StringCtor);
-void Heap::StringCtor::init(QV4::ExecutionContext *scope)
+void Heap::StringCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("String"));
+ Heap::FunctionObject::init(engine, QStringLiteral("String"));
}
ReturnedValue StringCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 451a989ef4..73c2bd7b34 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -44,7 +44,7 @@ DECLARE_HEAP_OBJECT(StringObject, Object) {
};
struct StringCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4symbol.cpp b/src/qml/jsruntime/qv4symbol.cpp
index 5f7ec89fd2..85ef57f680 100644
--- a/src/qml/jsruntime/qv4symbol.cpp
+++ b/src/qml/jsruntime/qv4symbol.cpp
@@ -19,9 +19,9 @@ void Heap::Symbol::init(const QString &s)
identifier = PropertyKey::fromStringOrSymbol(internalClass->engine, this);
}
-void Heap::SymbolCtor::init(QV4::ExecutionContext *scope)
+void Heap::SymbolCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Symbol"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Symbol"));
}
void Heap::SymbolObject::init(const QV4::Symbol *s)
diff --git a/src/qml/jsruntime/qv4symbol_p.h b/src/qml/jsruntime/qv4symbol_p.h
index e56510bd69..29a0189b69 100644
--- a/src/qml/jsruntime/qv4symbol_p.h
+++ b/src/qml/jsruntime/qv4symbol_p.h
@@ -25,7 +25,7 @@ namespace QV4 {
namespace Heap {
struct SymbolCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct Symbol : StringOrSymbol {
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index 6c72eaba5f..9c752f43bb 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -236,9 +236,9 @@ const TypedArrayOperations operations[NTypedArrayTypes] = {
};
-void Heap::TypedArrayCtor::init(QV4::ExecutionContext *scope, TypedArray::Type t)
+void Heap::TypedArrayCtor::init(QV4::ExecutionEngine *engine, TypedArray::Type t)
{
- Heap::FunctionObject::init(scope, QLatin1String(operations[t].name));
+ Heap::FunctionObject::init(engine, QLatin1String(operations[t].name));
type = t;
}
@@ -762,8 +762,6 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_fill(const FunctionObject *b,
fin = static_cast<uint>(std::min(relativeEnd, dlen));
}
- double val = argc ? argv[0].toNumber() : std::numeric_limits<double>::quiet_NaN();
- Value value = Value::fromDouble(val);
if (scope.hasException() || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
@@ -771,6 +769,14 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_fill(const FunctionObject *b,
uint bytesPerElement = v->bytesPerElement();
uint byteOffset = v->byteOffset();
+ Value value;
+ if (!argc)
+ value.setDouble(std::numeric_limits<double>::quiet_NaN());
+ else if (argv[0].isNumber())
+ value = argv[0];
+ else
+ value.setDouble(argv[0].toNumber());
+
while (k < fin) {
v->d()->type->write(data + byteOffset + k * bytesPerElement, value);
k++;
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 9747eac411..50db9610c7 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -90,7 +90,7 @@ struct IntrinsicTypedArrayCtor : FunctionObject {
};
struct TypedArrayCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope, TypedArray::Type t);
+ void init(ExecutionEngine *engine, TypedArray::Type t);
TypedArray::Type type;
};
@@ -141,8 +141,6 @@ struct IntrinsicTypedArrayCtor: FunctionObject
{
V4_OBJECT2(IntrinsicTypedArrayCtor, FunctionObject)
- static constexpr VTable::Call virtualCall = nullptr;
-
static ReturnedValue method_of(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_from(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
diff --git a/src/qml/jsruntime/qv4urlobject.cpp b/src/qml/jsruntime/qv4urlobject.cpp
index 4ece91a2a2..89c8b9cda2 100644
--- a/src/qml/jsruntime/qv4urlobject.cpp
+++ b/src/qml/jsruntime/qv4urlobject.cpp
@@ -18,9 +18,9 @@ DEFINE_OBJECT_VTABLE(UrlSearchParamsObject);
DEFINE_OBJECT_VTABLE(UrlSearchParamsCtor);
-void Heap::UrlCtor::init(QV4::ExecutionContext *scope)
+void Heap::UrlCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QLatin1String("URL"));
+ Heap::FunctionObject::init(engine, QLatin1String("URL"));
}
void UrlPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -750,9 +750,9 @@ ReturnedValue UrlCtor::virtualCallAsConstructor(const FunctionObject *that, cons
}
-void Heap::UrlSearchParamsCtor::init(QV4::ExecutionContext *scope)
+void Heap::UrlSearchParamsCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QLatin1String("URLSearchParams"));
+ Heap::FunctionObject::init(engine, QLatin1String("URLSearchParams"));
}
void UrlSearchParamsPrototype::init(ExecutionEngine *engine, Object *ctor)
diff --git a/src/qml/jsruntime/qv4urlobject_p.h b/src/qml/jsruntime/qv4urlobject_p.h
index d45b74fcaa..b3b76e1158 100644
--- a/src/qml/jsruntime/qv4urlobject_p.h
+++ b/src/qml/jsruntime/qv4urlobject_p.h
@@ -47,7 +47,7 @@ DECLARE_HEAP_OBJECT(UrlObject, Object)
struct UrlCtor : FunctionObject
{
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
// clang-format off
@@ -66,7 +66,7 @@ DECLARE_HEAP_OBJECT(UrlSearchParamsObject, Object)
struct UrlSearchParamsCtor : FunctionObject
{
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index f2d01c56cd..eaa57a36aa 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -309,7 +309,10 @@ inline bool Value::isObject() const
inline bool Value::isFunctionObject() const
{
HeapBasePtr b = heapObject();
- return b && b->internalClass->vtable->isFunctionObject;
+ if (!b)
+ return false;
+ const VTable *vtable = b->internalClass->vtable;
+ return vtable->call || vtable->callAsConstructor;
}
inline bool Value::isPrimitive() const
diff --git a/src/qml/jsruntime/qv4vtable_p.h b/src/qml/jsruntime/qv4vtable_p.h
index 8ec8c87a31..0532fdc32d 100644
--- a/src/qml/jsruntime/qv4vtable_p.h
+++ b/src/qml/jsruntime/qv4vtable_p.h
@@ -64,7 +64,7 @@ struct VTable
quint8 isExecutionContext;
quint8 isString;
quint8 isObject;
- quint8 isFunctionObject;
+ quint8 isTailCallable;
quint8 isErrorObject;
quint8 isArrayData;
quint8 isStringOrSymbol;
@@ -110,20 +110,38 @@ template<class Class>
constexpr VTable::CallWithMetaTypes vtableMetaTypesCallEntry()
{
// If Class overrides virtualCallWithMetaTypes, return that.
- // Otherwise, if it overrides virtualCall, return nullptr so that we convert calls.
+ // Otherwise, if it overrides virtualCall, return convertAndCall.
// Otherwise, just return whatever the base class had.
- // A simple != is not considered constexpr, so we have to jump through some hoops.
- if constexpr (!std::is_same_v<
- VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
- VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>) {
- return Class::virtualCallWithMetaTypes;
- }
-
- if constexpr (!std::is_same_v<
- VTableCallWrapper<Class::virtualCall>,
- VTableCallWrapper<Class::SuperClass::virtualCall>>) {
- return nullptr;
+ // A simple == on methods is not considered constexpr, so we have to jump through some hoops.
+
+ static_assert(
+ std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>
+ || !std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<nullptr>>,
+ "You mustn't override virtualCallWithMetaTypes with nullptr");
+
+ static_assert(
+ std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualConvertAndCall>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualConvertAndCall>>
+ || !std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualConvertAndCall>,
+ VTableCallWithMetaTypesWrapper<nullptr>>,
+ "You mustn't override virtualConvertAndCall with nullptr");
+
+ if constexpr (
+ std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>
+ && !std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>) {
+ // Converting from metatypes to JS signature is easy.
+ return Class::virtualConvertAndCall;
}
return Class::virtualCallWithMetaTypes;
@@ -133,21 +151,27 @@ template<class Class>
constexpr VTable::Call vtableJsTypesCallEntry()
{
// If Class overrides virtualCall, return that.
- // Otherwise, if it overrides virtualCallWithMetaTypes, return nullptr so that we convert calls.
+ // Otherwise, if it overrides virtualCallWithMetaTypes, fail.
+ // (We cannot determine the target types to call virtualCallWithMetaTypes in that case)
// Otherwise, just return whatever the base class had.
- // A simple != is not considered constexpr, so we have to jump through some hoops.
- if constexpr (!std::is_same_v<
- VTableCallWrapper<Class::virtualCall>,
- VTableCallWrapper<Class::SuperClass::virtualCall>>) {
- return Class::virtualCall;
- }
+ // A simple == on methods is not considered constexpr, so we have to jump through some hoops.
- if constexpr (!std::is_same_v<
- VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
- VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>) {
- return nullptr;
- }
+ static_assert(
+ !std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>
+ || std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>,
+ "If you override virtualCallWithMetaTypes, override virtualCall, too");
+
+ static_assert(
+ std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>
+ || VTableCallWrapper<Class::virtualCall>::c != nullptr,
+ "You mustn't override virtualCall with nullptr");
return Class::virtualCall;
}
@@ -174,6 +198,7 @@ protected:
static constexpr VTable::Call virtualCall = nullptr;
static constexpr VTable::CallAsConstructor virtualCallAsConstructor = nullptr;
static constexpr VTable::CallWithMetaTypes virtualCallWithMetaTypes = nullptr;
+ static constexpr VTable::CallWithMetaTypes virtualConvertAndCall = nullptr;
static constexpr VTable::ResolveLookupGetter virtualResolveLookupGetter = nullptr;
static constexpr VTable::ResolveLookupSetter virtualResolveLookupSetter = nullptr;
@@ -196,7 +221,7 @@ protected:
classname::IsExecutionContext, \
classname::IsString, \
classname::IsObject, \
- classname::IsFunctionObject, \
+ classname::IsTailCallable, \
classname::IsErrorObject, \
classname::IsArrayData, \
classname::IsStringOrSymbol, \
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 8f6a6503fc..d740969131 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -56,10 +56,8 @@
#include <pthread_np.h>
#endif
-Q_LOGGING_CATEGORY(lcGcStats, "qt.qml.gc.statistics")
-Q_DECLARE_LOGGING_CATEGORY(lcGcStats)
-Q_LOGGING_CATEGORY(lcGcAllocatorStats, "qt.qml.gc.allocatorStats")
-Q_DECLARE_LOGGING_CATEGORY(lcGcAllocatorStats)
+Q_STATIC_LOGGING_CATEGORY(lcGcStats, "qt.qml.gc.statistics")
+Q_STATIC_LOGGING_CATEGORY(lcGcAllocatorStats, "qt.qml.gc.allocatorStats")
using namespace WTF;
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index cdb3dde5c6..aa95f6302f 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -1007,7 +1007,7 @@ again:
int Lexer::scanString(ScanStringMode mode)
{
- QChar quote = (mode == TemplateContinuation) ? QChar(TemplateHead) : QChar(mode);
+ const char16_t quote = mode == TemplateContinuation ? TemplateHead : mode;
// we actually use T_STRING_LITERAL also for multiline strings, should we want to
// change that we should set it to:
// _state.tokenKind == T_PARTIAL_SINGLE_QUOTE_STRING_LITERAL ||
@@ -1220,7 +1220,7 @@ int Lexer::scanNumber(QChar ch)
_state.errorCode = IllegalNumber;
_errorMessage = QCoreApplication::translate(
"QQmlParser",
- "There can be at most one numeric separator beetwen digits"
+ "There can be at most one numeric separator between digits"
);
return false;
}
diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h
index b6144e8894..d991bcff58 100644
--- a/src/qml/parser/qqmljslexer_p.h
+++ b/src/qml/parser/qqmljslexer_p.h
@@ -240,7 +240,7 @@ private:
int scanToken();
int scanNumber(QChar ch);
int scanVersionNumber(QChar ch);
- enum ScanStringMode {
+ enum ScanStringMode : char16_t {
SingleQuote = '\'',
DoubleQuote = '"',
TemplateHead = '`',
diff --git a/src/qml/qml/ftw/qqmlnullablevalue_p.h b/src/qml/qml/ftw/qqmlnullablevalue_p.h
index 9a3f032b68..62899e4644 100644
--- a/src/qml/qml/ftw/qqmlnullablevalue_p.h
+++ b/src/qml/qml/ftw/qqmlnullablevalue_p.h
@@ -30,7 +30,7 @@ struct QQmlNullableValue
{}
QQmlNullableValue(QQmlNullableValue<T> &&o) noexcept
- : m_value(std::move(o.value))
+ : m_value(std::move(o.m_value))
, m_isNull(std::exchange(o.m_isNull, true))
{}
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp
index 57f91b6b4d..38bd99a640 100644
--- a/src/qml/qml/ftw/qqmlthread.cpp
+++ b/src/qml/qml/ftw/qqmlthread.cpp
@@ -240,7 +240,7 @@ void QQmlThread::wait()
bool QQmlThread::isThisThread() const
{
- return QThread::currentThreadId() == static_cast<QThreadPrivate *>(QObjectPrivate::get(d))->threadData.loadRelaxed()->threadId.loadRelaxed();
+ return d->isCurrentThread();
}
QThread *QQmlThread::thread() const
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index eb716671b1..0642cb28e3 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -10,7 +10,7 @@
#include <private/qqmlcomponent_p.h>
#include <private/qqmlengine_p.h>
#include <private/qqmlfinalizer_p.h>
-#include <private/qqmlloggingcategory_p.h>
+#include <private/qqmlloggingcategorybase_p.h>
#include <private/qqmlmetatype_p.h>
#include <private/qqmlmetatypedata_p.h>
#include <private/qqmltype_p_p.h>
@@ -27,9 +27,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQml);
-Q_DECLARE_LOGGING_CATEGORY(lcJs);
-
/*!
\internal
@@ -356,7 +353,24 @@ void qmlUnregisterModuleImport(const char *uri, int moduleMajor,
//From qqml.h
int qmlTypeId(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
{
- return QQmlMetaType::typeId(uri, QTypeRevision::fromVersion(versionMajor, versionMinor), qmlName);
+ auto revision = QTypeRevision::fromVersion(versionMajor, versionMinor);
+ int id = QQmlMetaType::typeId(uri, revision, qmlName);
+ if (id != -1)
+ return id;
+ /* If the module hasn't been imported yet, we might not have the id of a
+ singleton at this point. To obtain it, we need an engine in order to
+ to do the resolution steps.
+ This is expensive, but we assume that users don't constantly query invalid
+ Types; internal code should use QQmlMetaType API.
+ */
+ QQmlEngine engine;
+ auto *enginePriv = QQmlEnginePrivate::get(&engine);
+ auto loadHelper = QQml::makeRefPointer<LoadHelper>(&enginePriv->typeLoader, uri);
+ auto type = loadHelper->resolveType(qmlName).type;
+ if (type.availableInVersion(revision))
+ return type.index();
+ else
+ return -1;
}
static bool checkSingletonInstance(QQmlEngine *engine, QObject *instance)
@@ -1677,10 +1691,10 @@ const QLoggingCategory *AOTCompiledContext::resolveLoggingCategory(QObject *wrap
{
if (wrapper) {
// We have to check this here because you may pass a plain QObject that only
- // turns out to be a QQmlLoggingCategory at run time.
- if (QQmlLoggingCategory *qQmlLoggingCategory
- = qobject_cast<QQmlLoggingCategory *>(wrapper)) {
- QLoggingCategory *loggingCategory = qQmlLoggingCategory->category();
+ // turns out to be a QQmlLoggingCategoryBase at run time.
+ if (QQmlLoggingCategoryBase *qQmlLoggingCategory
+ = qobject_cast<QQmlLoggingCategoryBase *>(wrapper)) {
+ const QLoggingCategory *loggingCategory = qQmlLoggingCategory->category();
*ok = true;
if (!loggingCategory) {
engine->handle()->throwError(
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 47f8e5c429..4dfee0a3c6 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -533,7 +533,8 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
delayedError()->setErrorDescription(QLatin1String("Unable to assign [undefined] to ")
+ typeName);
return false;
- } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>()) {
+ } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
+ f && !f->as<QV4::QQmlTypeWrapper>()) {
if (f->isBinding())
delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
else
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 3f9ce26764..0bac2f45a2 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -62,7 +62,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int
function += QLatin1String(") { ") + expression + QLatin1String(" })");
QV4::Scope valueScope(v4);
- QV4::ScopedFunctionObject f(valueScope, evalFunction(context(), scopeObject(), function, fileName, line));
+ QV4::Scoped<QV4::JavaScriptFunctionObject> f(
+ valueScope, evalFunction(context(), scopeObject(), function, fileName, line));
QV4::ScopedContext context(valueScope, f->scope());
setupFunction(context, f->function());
}
@@ -107,7 +108,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int
// we need to run the outer function to get the nested one.
if (function->isClosureWrapper()) {
bool isUndefined = false;
- QV4::ScopedFunctionObject result(
+ QV4::Scoped<QV4::JavaScriptFunctionObject> result(
valueScope, QQmlJavaScriptExpression::evaluate(&isUndefined));
Q_ASSERT(!isUndefined);
diff --git a/src/qml/qml/qqmlbuiltinfunctions.cpp b/src/qml/qml/qqmlbuiltinfunctions.cpp
index de37cc18be..0d31561e84 100644
--- a/src/qml/qml/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/qqmlbuiltinfunctions.cpp
@@ -3,52 +3,39 @@
#include "qqmlbuiltinfunctions_p.h"
-#include <QtQml/qqmlcomponent.h>
-#include <QtQml/qqmlfile.h>
-#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
-#include <private/qqmlloggingcategory_p.h>
-#include <private/qqmlstringconverters_p.h>
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
-#endif
-#include <private/qqmldelayedcallqueue_p.h>
-#include <QFileInfo>
-
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
-#include <private/qqmlglobal_p.h>
-
+#include <private/qqmldelayedcallqueue_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlloggingcategorybase_p.h>
#include <private/qqmlplatform_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <private/qv4dateobject_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4include_p.h>
-#include <private/qv4context_p.h>
-#include <private/qv4stringobject_p.h>
-#include <private/qv4dateobject_p.h>
#include <private/qv4mm_p.h>
-#include <private/qv4jsonobject_p.h>
-#include <private/qv4objectproto_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4stackframe_p.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qdatetime.h>
+#include <QtQml/qqmlfile.h>
+
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qcryptographichash.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qpoint.h>
#include <QtCore/qrect.h>
#include <QtCore/qsize.h>
-#include <QtCore/qpoint.h>
+#include <QtCore/qstring.h>
#include <QtCore/qurl.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qloggingcategory.h>
-
-#include <QDebug>
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcRootProperties, "qt.qml.rootObjectProperties");
+Q_STATIC_LOGGING_CATEGORY(lcRootProperties, "qt.qml.rootObjectProperties");
Q_LOGGING_CATEGORY(lcQml, "qml");
Q_LOGGING_CATEGORY(lcJs, "js");
@@ -172,6 +159,7 @@ The following functions are also on the Qt object.
\li \c "android" - Android
\li \c "ios" - iOS
\li \c "tvos" - tvOS
+ \li \c "visionos" - visionOS
\li \c "linux" - Linux
\li \c "osx" - \macos
\li \c "qnx" - QNX (since Qt 5.9.3)
@@ -180,6 +168,9 @@ The following functions are also on the Qt object.
\li \c "wasm" - WebAssembly
\endlist
+ \note The property's value on \macos is "osx", regardless of Apple naming convention.
+ The returned value will be updated to "macos" for Qt 7.
+
\row
\li \c platform.pluginName
\li This is the name of the platform set on the QGuiApplication instance
@@ -229,7 +220,9 @@ The following functions are also on the Qt object.
The \c styleHints object provides platform-specific style hints and settings.
See the \l QStyleHints documentation for further details.
- You should access StyleHints via \l Application::styleHints instead.
+ You should access StyleHints via \l Application::styleHints instead, as
+ this provides better type information for tooling such as the
+ \l {Qt Quick Compiler}.
\note The \c styleHints object is only available when using the Qt Quick module.
*/
@@ -1472,11 +1465,12 @@ use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}.
*/
/*!
+\since 6.5
\qmlmethod Component Qt::createComponent(string moduleUri, string typeName, enumeration mode, QtObject parent)
\overload
Returns a \l Component object created for the type specified by \a moduleUri and \a typeName.
\qml
-import QtQuick
+import QtQml
QtObject {
id: root
property Component myComponent: Qt.createComponent("QtQuick", "Rectangle", Component.Asynchronous, root)
@@ -1616,14 +1610,21 @@ QLocale QtObject::locale(const QString &name) const
}
#endif
-void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *bindingFunction)
+void Heap::QQmlBindingFunction::init(const QV4::JavaScriptFunctionObject *bindingFunction)
{
Scope scope(bindingFunction->engine());
ScopedContext context(scope, bindingFunction->scope());
- FunctionObject::init(context, bindingFunction->function());
+ JavaScriptFunctionObject::init(context, bindingFunction->function());
this->bindingFunction.set(internalClass->engine, bindingFunction->d());
}
+ReturnedValue QQmlBindingFunction::virtualCall(
+ const FunctionObject *f, const Value *, const Value *, int)
+{
+ // Mark this as a callable object, so that we can perform the binding magic on it.
+ return f->engine()->throwTypeError(QStringLiteral("Bindings must not be called directly."));
+}
+
QQmlSourceLocation QQmlBindingFunction::currentLocation() const
{
QV4::CppStackFrame *frame = engine()->currentStackFrame;
@@ -1678,7 +1679,8 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction);
*/
QJSValue QtObject::binding(const QJSValue &function) const
{
- const QV4::FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(&function);
+ const QV4::JavaScriptFunctionObject *f
+ = QJSValuePrivate::asManagedType<JavaScriptFunctionObject>(&function);
QV4::ExecutionEngine *e = v4Engine();
if (!f) {
return QJSValuePrivate::fromReturnedValue(
@@ -1816,7 +1818,8 @@ static ReturnedValue writeToConsole(const FunctionObject *b, const Value *argv,
int start = 0;
if (argc > 0) {
if (const QObjectWrapper* wrapper = argv[0].as<QObjectWrapper>()) {
- if (QQmlLoggingCategory* category = qobject_cast<QQmlLoggingCategory*>(wrapper->object())) {
+ if (QQmlLoggingCategoryBase *category
+ = qobject_cast<QQmlLoggingCategoryBase *>(wrapper->object())) {
if (category->category())
loggingCategory = category->category();
else
@@ -1997,7 +2000,7 @@ ReturnedValue ConsoleObject::method_trace(const FunctionObject *b, const Value *
QV4::CppStackFrame *frame = v4->currentStackFrame;
QMessageLogger(frame->source().toUtf8().constData(), frame->lineNumber(),
frame->function().toUtf8().constData())
- .debug(v4->qmlEngine() ? lcQml : lcJs, "%s", qPrintable(stack));
+ .debug(v4->qmlEngine() ? lcQml() : lcJs(), "%s", qPrintable(stack));
return QV4::Encode::undefined();
}
@@ -2141,7 +2144,7 @@ ReturnedValue GlobalExtensions::method_qsTranslate(const FunctionObject *b, cons
}
/*!
- \qmlmethod string Qt::qsTranslateNoOp(string context, string sourceText, string disambiguation)
+ \qmlmethod string Qt::QT_TRANSLATE_NOOP(string context, string sourceText, string disambiguation)
Marks \a sourceText for dynamic translation in the given \a context; i.e, the stored \a sourceText
will not be altered.
@@ -2256,7 +2259,7 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value
}
/*!
- \qmlmethod string Qt::qsTrNoOp(string sourceText, string disambiguation)
+ \qmlmethod string Qt::QT_TR_NOOP(string sourceText, string disambiguation)
Marks \a sourceText for dynamic translation; i.e, the stored \a sourceText
will not be altered.
@@ -2337,7 +2340,7 @@ ReturnedValue GlobalExtensions::method_qsTrId(const FunctionObject *b, const Val
}
/*!
- \qmlmethod string Qt::qsTrIdNoOp(string id)
+ \qmlmethod string Qt::QT_TRID_NOOP(string id)
Marks \a id for dynamic translation.
diff --git a/src/qml/qml/qqmlbuiltinfunctions_p.h b/src/qml/qml/qqmlbuiltinfunctions_p.h
index 9ceedad28b..8d1cc75cb1 100644
--- a/src/qml/qml/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/qqmlbuiltinfunctions_p.h
@@ -31,6 +31,9 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQml);
+Q_DECLARE_LOGGING_CATEGORY(lcJs);
+
class Q_QML_EXPORT QtObject : public QObject
{
Q_OBJECT
@@ -46,7 +49,6 @@ class Q_QML_EXPORT QtObject : public QObject
QML_NAMED_ELEMENT(Qt)
QML_SINGLETON
QML_EXTENDED_NAMESPACE(Qt)
- QML_ADDED_IN_VERSION(2, 0)
Q_CLASSINFO("QML.StrictArguments", "true")
@@ -199,10 +201,10 @@ struct ConsoleObject : Object {
};
#define QQmlBindingFunctionMembers(class, Member) \
- Member(class, Pointer, FunctionObject *, bindingFunction)
-DECLARE_HEAP_OBJECT(QQmlBindingFunction, FunctionObject) {
+ Member(class, Pointer, JavaScriptFunctionObject *, bindingFunction)
+DECLARE_HEAP_OBJECT(QQmlBindingFunction, JavaScriptFunctionObject) {
DECLARE_MARKOBJECTS(QQmlBindingFunction)
- void init(const QV4::FunctionObject *bindingFunction);
+ void init(const QV4::JavaScriptFunctionObject *bindingFunction);
};
}
@@ -245,11 +247,14 @@ struct Q_QML_EXPORT GlobalExtensions {
};
-struct QQmlBindingFunction : public QV4::FunctionObject
+struct QQmlBindingFunction : public QV4::JavaScriptFunctionObject
{
- V4_OBJECT2(QQmlBindingFunction, FunctionObject)
+ V4_OBJECT2(QQmlBindingFunction, JavaScriptFunctionObject)
+
+ static ReturnedValue virtualCall(
+ const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
- Heap::FunctionObject *bindingFunction() const { return d()->bindingFunction; }
+ Heap::JavaScriptFunctionObject *bindingFunction() const { return d()->bindingFunction; }
QQmlSourceLocation currentLocation() const; // from caller stack trace
};
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index e063418de4..685b5cc62f 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -36,7 +36,7 @@ namespace {
Q_CONSTINIT thread_local int creationDepth = 0;
}
-Q_LOGGING_CATEGORY(lcQmlComponentGeneral, "qt.qml.qmlcomponent")
+Q_STATIC_LOGGING_CATEGORY(lcQmlComponentGeneral, "qt.qml.qmlcomponent")
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlcomponentandaliasresolver_p.h b/src/qml/qml/qqmlcomponentandaliasresolver_p.h
index a2758d385c..439c7d62d4 100644
--- a/src/qml/qml/qqmlcomponentandaliasresolver_p.h
+++ b/src/qml/qml/qqmlcomponentandaliasresolver_p.h
@@ -33,10 +33,14 @@ Q_DECLARE_LOGGING_CATEGORY(lcQmlTypeCompiler);
// to be located in surrounding components. That's why we have to do this with the component
// boundaries in mind.
+class QQmlComponentAndAliasResolverBase
+{
+ Q_DECLARE_TR_FUNCTIONS(QQmlComponentAndAliasResolverBase)
+};
+
template<typename ObjectContainer>
-class QQmlComponentAndAliasResolver
+class QQmlComponentAndAliasResolver : public QQmlComponentAndAliasResolverBase
{
- Q_DECLARE_TR_FUNCTIONS(QQmlComponentAndAliasResolver)
public:
using CompiledObject = typename ObjectContainer::CompiledObject;
using CompiledBinding = typename ObjectContainer::CompiledBinding;
@@ -191,7 +195,7 @@ QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::findAndRegisterImplici
continue;
if (!wrapImplicitComponent(binding))
- return error(binding, tr("Cannot wrap implicit component"));
+ return error(binding, QQmlComponentAndAliasResolverBase::tr("Cannot wrap implicit component"));
}
return QQmlError();
@@ -287,7 +291,7 @@ QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::resolve(int root)
}
if (!markAsComponent(i))
- return error(obj, tr("Cannot mark object as component"));
+ return error(obj, QQmlComponentAndAliasResolverBase::tr("Cannot mark object as component"));
// check if this object is the root
if (i == 0) {
@@ -301,14 +305,14 @@ QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::resolve(int root)
}
if (obj->functionCount() > 0)
- return error(obj, tr("Component objects cannot declare new functions."));
+ return error(obj, QQmlComponentAndAliasResolverBase::tr("Component objects cannot declare new functions."));
if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
- return error(obj, tr("Component objects cannot declare new properties."));
+ return error(obj, QQmlComponentAndAliasResolverBase::tr("Component objects cannot declare new properties."));
if (obj->signalCount() > 0)
- return error(obj, tr("Component objects cannot declare new signals."));
+ return error(obj, QQmlComponentAndAliasResolverBase::tr("Component objects cannot declare new signals."));
if (obj->bindingCount() == 0)
- return error(obj, tr("Cannot create empty component specification"));
+ return error(obj, QQmlComponentAndAliasResolverBase::tr("Cannot create empty component specification"));
const auto rootBinding = obj->bindingsBegin();
const auto bindingsEnd = obj->bindingsEnd();
@@ -319,12 +323,12 @@ QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::resolve(int root)
if (b->propertyNameIndex == 0)
continue;
- return error(b, tr("Component elements may not contain properties other than id"));
+ return error(b, QQmlComponentAndAliasResolverBase::tr("Component elements may not contain properties other than id"));
}
if (auto b = rootBinding;
b->type() != QV4::CompiledData::Binding::Type_Object || ++b != bindingsEnd) {
- return error(obj, tr("Invalid component body specification"));
+ return error(obj, QQmlComponentAndAliasResolverBase::tr("Invalid component body specification"));
}
// For the root object, we are going to collect ids/aliases and resolve them for as a
@@ -377,7 +381,7 @@ QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::collectIdsAndAliases(i
if (obj->idNameIndex != 0) {
if (m_idToObjectIndex.contains(obj->idNameIndex))
- return error(obj->locationOfIdProperty, tr("id is not unique"));
+ return error(obj->locationOfIdProperty, QQmlComponentAndAliasResolverBase::tr("id is not unique"));
setObjectId(objectIndex);
m_idToObjectIndex.insert(obj->idNameIndex, objectIndex);
}
@@ -459,7 +463,7 @@ QQmlError QQmlComponentAndAliasResolver<ObjectContainer>::resolveAliases(int com
const CompiledObject *obj = m_compiler->objectAt(m_objectsWithAliases.first());
for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
if (!alias->hasFlag(QV4::CompiledData::Alias::Resolved))
- return error(alias->location, tr("Circular alias reference detected"));
+ return error(alias->location, QQmlComponentAndAliasResolverBase::tr("Circular alias reference detected"));
}
}
diff --git a/src/qml/qml/qqmlcontextdata_p.h b/src/qml/qml/qqmlcontextdata_p.h
index c8e362ec8d..3aeabf72fa 100644
--- a/src/qml/qml/qqmlcontextdata_p.h
+++ b/src/qml/qml/qqmlcontextdata_p.h
@@ -292,6 +292,10 @@ public:
return m_typeCompilationUnit && m_typeCompilationUnit->valueTypesAreAddressable();
}
+ bool valueTypesAreAssertable() const {
+ return m_typeCompilationUnit && m_typeCompilationUnit->valueTypesAreAssertable();
+ }
+
private:
friend class QQmlGuardedContextData;
friend class QQmlContextPrivate;
diff --git a/src/qml/qml/qqmldatablob.cpp b/src/qml/qml/qqmldatablob.cpp
index 6b354c337f..0a520d5864 100644
--- a/src/qml/qml/qqmldatablob.cpp
+++ b/src/qml/qml/qqmldatablob.cpp
@@ -4,9 +4,10 @@
#include <private/qqmldatablob_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmlprofiler_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qqmltypedata_p.h>
#include <private/qqmltypeloader_p.h>
#include <private/qqmltypeloaderthread_p.h>
-#include <private/qqmlsourcecoordinate_p.h>
#include <QtQml/qqmlengine.h>
@@ -20,8 +21,6 @@
DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS);
-Q_DECLARE_LOGGING_CATEGORY(lcCycle)
-
QT_BEGIN_NAMESPACE
/*!
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index efd8519a58..ead8a717f5 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -126,8 +126,9 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::Executi
// if it's a qobject function wrapper, guard against qobject deletion
dfc.m_objectGuard = QQmlGuard<QObject>(functionData.first);
dfc.m_guarded = true;
- } else if (func->scope()->type == QV4::Heap::ExecutionContext::Type_QmlContext) {
- QV4::QmlContext::Data *g = static_cast<QV4::QmlContext::Data *>(func->scope());
+ } else if (const auto *js = func->as<QV4::JavaScriptFunctionObject>();
+ js && js->scope()->type == QV4::Heap::ExecutionContext::Type_QmlContext) {
+ QV4::QmlContext::Data *g = static_cast<QV4::QmlContext::Data *>(js->scope());
Q_ASSERT(g->qml()->scopeObject);
dfc.m_objectGuard = QQmlGuard<QObject>(g->qml()->scopeObject);
dfc.m_guarded = true;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index c7812059a1..14408c735b 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -4,57 +4,45 @@
#include "qqmlengine_p.h"
#include "qqmlengine.h"
-#include "qqmlcontext_p.h"
-#include "qqml.h"
-#include "qqmlcontext.h"
-#include "qqmlscriptstring.h"
-#include "qqmlglobal_p.h"
-#include "qqmlnotifier_p.h"
-#include "qqmlincubator.h"
-#include "qqmlabstracturlinterceptor.h"
-
-#include <private/qqmldirparser_p.h>
+#include <private/qqmlabstractbinding_p.h>
#include <private/qqmlboundsignal_p.h>
-#include <private/qqmljsdiagnosticmessage_p.h>
-#include <private/qqmltype_p_p.h>
+#include <private/qqmlcontext_p.h>
+#include <private/qqmlnotifier_p.h>
#include <private/qqmlpluginimporter_p.h>
-#include <QtCore/qstandardpaths.h>
-#include <QtCore/qmetaobject.h>
-#include <QDebug>
+#include <private/qqmlprofiler_p.h>
+#include <private/qqmlscriptdata_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qqmltypedata_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qqmlcomponent_p.h>
+
+#include <private/qobject_p.h>
+#include <private/qthread_p.h>
+
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlincubator.h>
+#include <QtQml/qqmlscriptstring.h>
+
#include <QtCore/qcoreapplication.h>
#include <QtCore/qcryptographichash.h>
#include <QtCore/qdir.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qstandardpaths.h>
#include <QtCore/qthread.h>
-#include <private/qthread_p.h>
-#include <private/qqmlscriptdata_p.h>
-#include <QtQml/private/qqmlcomponentattached_p.h>
-#include <QtQml/private/qqmlsourcecoordinate_p.h>
-#include <QtQml/private/qqmlcomponent_p.h>
#if QT_CONFIG(qml_network)
-#include "qqmlnetworkaccessmanagerfactory.h"
-#include <QNetworkAccessManager>
-#endif
-
-#include <private/qobject_p.h>
-#include <private/qmetaobject_p.h>
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
+#include <QtQml/qqmlnetworkaccessmanagerfactory.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
#endif
-#include <private/qqmlbind_p.h>
-#include <private/qqmlconnections_p.h>
-#if QT_CONFIG(qml_animation)
-#include <private/qqmltimer_p.h>
-#endif
-#include <private/qqmlplatform_p.h>
-#include <private/qqmlloggingcategory_p.h>
-#include <private/qv4sequenceobject_p.h>
#ifdef Q_OS_WIN // for %APPDATA%
# include <qt_windows.h>
# include <shlobj.h>
-# include <qlibrary.h>
+# include <QtCore/qlibrary.h>
# ifndef CSIDL_APPDATA
# define CSIDL_APPDATA 0x001a // <username>\Application Data
# endif
@@ -1881,6 +1869,24 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
return QJSValue(QJSValue::UndefinedValue);
}
QObject *o = component.beginCreate(q->rootContext());
+ auto *compPriv = QQmlComponentPrivate::get(&component);
+ if (compPriv->state.hasUnsetRequiredProperties()) {
+ /* We would only get the errors from the component after (complete)Create.
+ We can't call create, as we need to convertAndInsert before completeCreate (otherwise
+ tst_qqmllanguage::compositeSingletonCircular fails).
+ On the other hand, we don't want to call cnovertAndInsert if we have an error
+ So create the unset required component errors manually.
+ */
+ delete o;
+ const auto requiredProperties = compPriv->state.requiredProperties();
+ QList<QQmlError> errors (requiredProperties->size());
+ for (const auto &reqProp: *requiredProperties)
+ errors.push_back(QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(reqProp));
+ warning(errors);
+ v4engine()->throwError(QLatin1String("Due to the preceding error(s), Singleton \"%1\" could not be loaded.").arg(QString::fromUtf8(type.typeName())));
+ return QJSValue(QJSValue::UndefinedValue);
+ }
+
value = q->newQObject(o);
singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
component.completeCreate();
@@ -1945,7 +1951,7 @@ void QQmlEnginePrivate::executeRuntimeFunction(const QV4::ExecutableCompilationU
// different version of ExecutionEngine::callInContext() that returns a
// QV4::ReturnedValue with no arguments since they are not needed by the
// outer function anyhow
- QV4::ScopedFunctionObject result(scope,
+ QV4::Scoped<QV4::JavaScriptFunctionObject> result(scope,
v4->callInContext(function, thisObject, callContext, 0, nullptr));
Q_ASSERT(result->function());
Q_ASSERT(result->function()->compilationUnit == function->compilationUnit);
@@ -2042,7 +2048,7 @@ static inline QString shellNormalizeFileName(const QString &name)
bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
{
-#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
+#if defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
QFileInfo info(fileName);
const QString absolute = info.absoluteFilePath();
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index 1273067187..2e3fa5f86c 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -415,6 +415,10 @@ static QVariant byProperties(
if (source.metaType() == QMetaType::fromType<QJSValue>()) {
QJSValue val = source.value<QJSValue>();
+ // Generally, the GC might collect a Value at any point so that
+ // a `ScopedValue` should be used.
+ // In this case, the Value is tied to a `QJSValue` which is
+ // persistent to the GC and thus the cast is safe.
return byProperties(
targetMetaObject, targetMetaType, QV4::Value(QJSValuePrivate::asReturnedValue(&val)));
}
@@ -560,6 +564,10 @@ bool QQmlValueTypeProvider::populateValueType(
{
if (sourceMetaType == QMetaType::fromType<QJSValue>()) {
const QJSValue *val = static_cast<const QJSValue *>(source);
+ // Generally, the GC might collect a Value at any point so that
+ // a `ScopedValue` should be used.
+ // In this case, the Value is tied to a `QJSValue` which is
+ // persistent to the GC and thus the cast is safe.
return populateValueType(
targetMetaType, target, QV4::Value(QJSValuePrivate::asReturnedValue(val)));
}
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index 98fe2e6a79..5aa2f3ee6f 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -270,7 +270,6 @@ class Q_QML_EXPORT QQmlApplication : public QObject
Q_PROPERTY(QString organization READ organization WRITE setOrganization NOTIFY organizationChanged)
Q_PROPERTY(QString domain READ domain WRITE setDomain NOTIFY domainChanged)
QML_ANONYMOUS
- QML_ADDED_IN_VERSION(2, 0)
public:
QQmlApplication(QObject* parent=nullptr);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 86380294ba..521c598938 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -911,21 +911,31 @@ QTypeRevision QQmlImports::importExtension(
return QTypeRevision();
}
- if (qmldir->plugins().isEmpty()) {
- // If the qmldir does not register a plugin, we might still have declaratively
- // registered types (if we are dealing with an application instead of a library)
- if (!QQmlMetaType::typeModule(uri, version))
- QQmlMetaType::qmlRegisterModuleTypes(uri);
+ if (qmldir->plugins().isEmpty())
return validVersion(version);
- }
QQmlPluginImporter importer(
uri, version, typeLoader->importDatabase(), qmldir, typeLoader, errors);
return importer.importPlugins();
}
+void QQmlImports::registerBuiltinModuleTypes(
+ const QQmlTypeLoaderQmldirContent &qmldir, QTypeRevision version)
+{
+ if (!qmldir.plugins().isEmpty())
+ return;
+
+ // If the qmldir does not register a plugin, we might still have declaratively
+ // registered types (if we are dealing with an application instead of a library)
+
+ const QString qmldirUri = qmldir.typeNamespace();
+ if (!QQmlMetaType::typeModule(qmldirUri, version))
+ QQmlMetaType::qmlRegisterModuleTypes(qmldirUri);
+}
+
QString QQmlImports::redirectQmldirContent(
- QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir)
+ QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir,
+ QQmlImportInstance *inserted)
{
const QString preferredPath = qmldir->preferredPath();
const QString url = preferredPath.startsWith(u':')
@@ -938,6 +948,10 @@ QString QQmlImports::redirectQmldirContent(
// Ignore errors: If the qmldir doesn't exist, stick to the old one.
if (redirected.hasContent() && !redirected.hasError())
*qmldir = std::move(redirected);
+
+ if (const QString qmldirUri = qmldir->typeNamespace(); !qmldirUri.isEmpty())
+ inserted->uri = qmldirUri;
+
return url;
}
@@ -1179,9 +1193,11 @@ QTypeRevision QQmlImports::addLibraryImport(
return QTypeRevision();
const QString resolvedUrl = qmldir.hasRedirection()
- ? redirectQmldirContent(typeLoader, &qmldir)
+ ? redirectQmldirContent(typeLoader, &qmldir, inserted)
: qmldirUrl;
+ registerBuiltinModuleTypes(qmldir, version);
+
if (!inserted->setQmldirContent(resolvedUrl, qmldir, nameSpace, errors))
return QTypeRevision();
}
@@ -1362,7 +1378,9 @@ QTypeRevision QQmlImports::addFileImport(
return QTypeRevision();
if (qmldir.hasRedirection())
- url = redirectQmldirContent(typeLoader, &qmldir);
+ url = redirectQmldirContent(typeLoader, &qmldir, inserted);
+
+ registerBuiltinModuleTypes(qmldir, version);
if (!inserted->setQmldirContent(url, qmldir, nameSpace, errors))
return QTypeRevision();
@@ -1404,9 +1422,11 @@ QTypeRevision QQmlImports::updateQmldirContent(
return QTypeRevision();
const QString resolvedUrl = qmldir.hasRedirection()
- ? redirectQmldirContent(typeLoader, &qmldir)
+ ? redirectQmldirContent(typeLoader, &qmldir, import)
: qmldirUrl;
+ registerBuiltinModuleTypes(qmldir, version);
+
if (import->setQmldirContent(resolvedUrl, qmldir, nameSpace, errors)) {
if (import->qmlDirComponents.isEmpty() && import->qmlDirScripts.isEmpty()) {
// The implicit import qmldir can be empty, and plugins have no extra versions
@@ -1516,8 +1536,9 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
// 6. $QML_IMPORT_PATH
// 7. QLibraryInfo::QmlImportsPath
- QString installImportsPath = QLibraryInfo::path(QLibraryInfo::QmlImportsPath);
- addImportPath(installImportsPath);
+ const auto paths = QLibraryInfo::paths(QLibraryInfo::QmlImportsPath);
+ for (const auto &installImportsPath: paths)
+ addImportPath(installImportsPath);
auto addEnvImportPath = [this](const char *var) {
if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var))) {
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index ef9b4b3422..3d28c78ec6 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -235,7 +235,12 @@ private:
QQmlTypeLoader *typeLoader, const QString &uri, QTypeRevision version,
const QQmlTypeLoaderQmldirContent *qmldir, QList<QQmlError> *errors);
- QString redirectQmldirContent(QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir);
+ void registerBuiltinModuleTypes(
+ const QQmlTypeLoaderQmldirContent &qmldir, QTypeRevision version);
+
+ QString redirectQmldirContent(
+ QQmlTypeLoader *typeLoader, QQmlTypeLoaderQmldirContent *qmldir,
+ QQmlImportInstance *inserted);
bool getQmldirContent(
QQmlTypeLoader *typeLoader, const QString &qmldirIdentifier, const QString &uri,
diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp
index b29ce185ef..e1019b804f 100644
--- a/src/qml/qml/qqmlirloader.cpp
+++ b/src/qml/qml/qqmlirloader.cpp
@@ -85,6 +85,8 @@ void QQmlIRLoader::load()
valueTypeBehavior |= Pragma::Copy;
if (unit->flags & QV4::CompiledData::Unit::ValueTypesAddressable)
valueTypeBehavior |= Pragma::Addressable;
+ if (unit->flags & QV4::CompiledData::Unit::ValueTypesAssertable)
+ valueTypeBehavior |= Pragma::Assertable;
if (valueTypeBehavior)
createValueTypePragma(Pragma::ValueTypeBehavior, valueTypeBehavior);
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 5d26bf8a68..82c65ccf82 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -54,13 +54,14 @@ private:
static QV4::ReturnedValue method_toLocaleCurrencyString(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
};
-
-namespace QQmlLocale
+// This needs to be a struct so that we can derive from QLocale and inherit its enums. Then we can
+// use it as extension in QQmlLocaleEnums and expose all the enums in one go, without duplicating
+// any in different qmltypes files.
+struct Q_QML_EXPORT QQmlLocale : public QLocale
{
- Q_NAMESPACE_EXPORT(Q_QML_EXPORT)
- QML_NAMED_ELEMENT(Locale)
- QML_ADDED_IN_VERSION(2, 2)
- QML_NAMESPACE_EXTENDED(QLocale)
+ Q_GADGET
+ QML_ANONYMOUS
+public:
// Qt defines Sunday as 7, but JS Date assigns Sunday 0
enum DayOfWeek {
@@ -72,11 +73,13 @@ namespace QQmlLocale
Friday = Qt::Friday,
Saturday = Qt::Saturday
};
- Q_ENUM_NS(DayOfWeek)
+ Q_ENUM(DayOfWeek)
- Q_QML_EXPORT QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName);
- Q_QML_EXPORT void registerStringLocaleCompare(QV4::ExecutionEngine *engine);
- Q_QML_EXPORT QV4::ReturnedValue method_localeCompare(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
+ static QV4::ReturnedValue locale(QV4::ExecutionEngine *engine, const QString &localeName);
+ static void registerStringLocaleCompare(QV4::ExecutionEngine *engine);
+ static QV4::ReturnedValue method_localeCompare(
+ const QV4::FunctionObject *, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc);
};
struct DayOfWeekList
diff --git a/src/qml/qml/qqmlloggingcategorybase_p.h b/src/qml/qml/qqmlloggingcategorybase_p.h
new file mode 100644
index 0000000000..4a3c4cf6aa
--- /dev/null
+++ b/src/qml/qml/qqmlloggingcategorybase_p.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLLOGGINGCATEGORYBASE_P_H
+#define QQMLLOGGINGCATEGORYBASE_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 <QtQml/qqml.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qloggingcategory.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QML_EXPORT QQmlLoggingCategoryBase : public QObject
+{
+ Q_OBJECT
+ QML_ANONYMOUS
+
+public:
+ QQmlLoggingCategoryBase(QObject *parent = nullptr) : QObject(parent) {}
+
+ const QLoggingCategory *category() const { return m_category.get(); }
+ void setCategory(const char *name, QtMsgType type)
+ {
+ m_category = std::make_unique<QLoggingCategory>(name, type);
+ }
+
+private:
+ std::unique_ptr<QLoggingCategory> m_category;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLLOGGINGCATEGORYBASE_P_H
diff --git a/src/qml/qml/qqmlmetamoduleregistration.cpp b/src/qml/qml/qqmlmetamoduleregistration.cpp
deleted file mode 100644
index 8e55b62b3a..0000000000
--- a/src/qml/qml/qqmlmetamoduleregistration.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include <private/qtqmlglobal_p.h>
-#include <qqmlmoduleregistration.h>
-#include <qqml.h>
-
-QT_BEGIN_NAMESPACE
-
-// Provide the type registration for QtQml here, in libQtQml.so.
-// This way we get a completely functional QtQml module and don't have to
-// rely on the plugin to be loaded.
-// In CMakeLists.txt we've specified NO_GENERATE_QMLTYPES to prevent
-// the generation of an extra type registration file.
-Q_QML_EXPORT void qml_register_types_QtQml()
-{
- // ### Qt7: Handle version 6 like version 2.
- qmlRegisterModule("QtQml", 2, 0);
- qmlRegisterModule("QtQml", 2, 254);
- qmlRegisterModule("QtQml", QT_VERSION_MAJOR, 0);
- qmlRegisterModule("QtQml", QT_VERSION_MAJOR, QT_VERSION_MINOR);
-}
-
-static const QQmlModuleRegistration registration("QtQml", qml_register_types_QtQml);
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 1175bde3db..f53aa2c28a 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -6,6 +6,7 @@
#include <private/qqmlextensionplugin_p.h>
#include <private/qqmlmetatypedata_p.h>
#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qqmlscriptblob_p.h>
#include <private/qqmltype_p_p.h>
#include <private/qqmltypeloader_p.h>
#include <private/qqmltypemodule_p.h>
@@ -16,8 +17,7 @@
#include <QtCore/qmutex.h>
#include <QtCore/qloggingcategory.h>
-Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
-Q_LOGGING_CATEGORY(lcTypeRegistration, "qt.qml.typeregistration")
+Q_STATIC_LOGGING_CATEGORY(lcTypeRegistration, "qt.qml.typeregistration")
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index a9b9140390..cc019949de 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -34,7 +34,7 @@
#include <QScopedValueRollback>
#include <QLoggingCategory>
-Q_LOGGING_CATEGORY(lcQmlDefaultMethod, "qt.qml.defaultmethod")
+Q_STATIC_LOGGING_CATEGORY(lcQmlDefaultMethod, "qt.qml.defaultmethod")
QT_USE_NAMESPACE
diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp
index dbd54b5f11..dd52ee2090 100644
--- a/src/qml/qml/qqmlplatform.cpp
+++ b/src/qml/qml/qqmlplatform.cpp
@@ -22,13 +22,18 @@ QQmlPlatform::~QQmlPlatform()
QString QQmlPlatform::os()
{
+ // ### Qt7: Consider implementing in terms of QSysInfo
+
#if defined(Q_OS_ANDROID)
return QStringLiteral("android");
#elif defined(Q_OS_IOS)
return QStringLiteral("ios");
#elif defined(Q_OS_TVOS)
return QStringLiteral("tvos");
-#elif defined(Q_OS_MAC)
+#elif defined(Q_OS_VISIONOS)
+ return QStringLiteral("visionos");
+#elif defined(Q_OS_MACOS)
+ // ### Qt7: Replace with "macos"
return QStringLiteral("osx");
#elif defined(Q_OS_WIN)
return QStringLiteral("windows");
diff --git a/src/qml/qml/qqmlplatform_p.h b/src/qml/qml/qqmlplatform_p.h
index b8d2167fd5..9905f6330c 100644
--- a/src/qml/qml/qqmlplatform_p.h
+++ b/src/qml/qml/qqmlplatform_p.h
@@ -27,7 +27,6 @@ class Q_QML_EXPORT QQmlPlatform : public QObject
Q_PROPERTY(QString os READ os CONSTANT)
Q_PROPERTY(QString pluginName READ pluginName CONSTANT)
QML_ANONYMOUS
- QML_ADDED_IN_VERSION(2, 0)
public:
explicit QQmlPlatform(QObject *parent = nullptr);
diff --git a/src/qml/qml/qqmlpluginimporter.cpp b/src/qml/qml/qqmlpluginimporter.cpp
index 24f12891b9..091cd28b73 100644
--- a/src/qml/qml/qqmlpluginimporter.cpp
+++ b/src/qml/qml/qqmlpluginimporter.cpp
@@ -18,8 +18,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQmlImport)
-
struct QmlPlugin {
std::unique_ptr<QPluginLoader> loader;
};
diff --git a/src/qml/qml/qqmlproperty.h b/src/qml/qml/qqmlproperty.h
index 0878034bab..cbe5eb21ad 100644
--- a/src/qml/qml/qqmlproperty.h
+++ b/src/qml/qml/qqmlproperty.h
@@ -23,7 +23,6 @@ class Q_QML_EXPORT QQmlProperty
{
Q_GADGET
QML_ANONYMOUS
- QML_ADDED_IN_VERSION(2, 15)
Q_PROPERTY(QObject *object READ object CONSTANT FINAL)
Q_PROPERTY(QString name READ name CONSTANT FINAL)
diff --git a/src/qml/qml/qqmlpropertybinding.cpp b/src/qml/qml/qqmlpropertybinding.cpp
index c8a7e6256a..35fd9c5963 100644
--- a/src/qml/qml/qqmlpropertybinding.cpp
+++ b/src/qml/qml/qqmlpropertybinding.cpp
@@ -18,7 +18,7 @@ QT_BEGIN_NAMESPACE
using namespace Qt::Literals::StringLiterals;
-Q_LOGGING_CATEGORY(lcQQPropertyBinding, "qt.qml.propertybinding");
+Q_STATIC_LOGGING_CATEGORY(lcQQPropertyBinding, "qt.qml.propertybinding");
QUntypedPropertyBinding QQmlPropertyBinding::create(const QQmlPropertyData *pd, QV4::Function *function,
QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt,
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index a225f94a3f..805113ad97 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -95,7 +95,6 @@ void QQmlPropertyData::load(const QMetaMethod &m)
case QMetaMethod::Constructor:
m_flags.setIsSignal(false);
m_flags.setIsConstructor(true);
- setPropType(QMetaType::fromType<QObject *>());
break;
default:
m_flags.setIsSignal(false);
@@ -687,28 +686,9 @@ const QQmlPropertyData *QQmlPropertyCache::findProperty(
return nullptr;
}
-QString QQmlPropertyData::name(QObject *object) const
-{
- if (!object)
- return QString();
-
- return name(object->metaObject());
-}
-QString QQmlPropertyData::name(const QMetaObject *metaObject) const
-{
- if (!metaObject || coreIndex() == -1)
- return QString();
- if (isFunction()) {
- QMetaMethod m = metaObject->method(coreIndex());
- return QString::fromUtf8(m.name().constData());
- } else {
- QMetaProperty p = metaObject->property(coreIndex());
- return QString::fromUtf8(p.name());
- }
-}
bool QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
{
diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h
index 0fa7984f05..bdfa41ab7a 100644
--- a/src/qml/qml/qqmlpropertydata_p.h
+++ b/src/qml/qml/qqmlpropertydata_p.h
@@ -338,8 +338,17 @@ public:
static Flags flagsForProperty(const QMetaProperty &);
void load(const QMetaProperty &);
void load(const QMetaMethod &);
- QString name(QObject *) const;
- QString name(const QMetaObject *) const;
+
+ QString name(QObject *object) const { return object ? name(object->metaObject()) : QString(); }
+ QString name(const QMetaObject *metaObject) const
+ {
+ if (!metaObject || m_coreIndex == -1)
+ return QString();
+
+ return QString::fromUtf8(isFunction()
+ ? metaObject->method(m_coreIndex).name().constData()
+ : metaObject->property(m_coreIndex).name());
+ }
bool markAsOverrideOf(QQmlPropertyData *predecessor);
diff --git a/src/qml/qml/qqmlscriptblob.cpp b/src/qml/qml/qqmlscriptblob.cpp
index fa9a41e801..5f29cd25a9 100644
--- a/src/qml/qml/qqmlscriptblob.cpp
+++ b/src/qml/qml/qqmlscriptblob.cpp
@@ -12,11 +12,10 @@
#include <QtCore/qloggingcategory.h>
-Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
-Q_LOGGING_CATEGORY(DBG_DISK_CACHE, "qt.qml.diskcache")
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(DBG_DISK_CACHE, "qt.qml.diskcache")
+
QQmlScriptBlob::QQmlScriptBlob(const QUrl &url, QQmlTypeLoader *loader)
: QQmlTypeLoader::Blob(url, JavaScriptFile, loader)
, m_isModule(url.path().endsWith(QLatin1String(".mjs")))
diff --git a/src/qml/qml/qqmlscriptblob_p.h b/src/qml/qml/qqmlscriptblob_p.h
index 59f969859b..9abc843de3 100644
--- a/src/qml/qml/qqmlscriptblob_p.h
+++ b/src/qml/qml/qqmlscriptblob_p.h
@@ -18,6 +18,7 @@
#include <private/qqmltypeloader_p.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
class QQmlScriptData;
class Q_AUTOTEST_EXPORT QQmlScriptBlob : public QQmlTypeLoader::Blob
diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp
index cdabd6d5bc..94e6e8f351 100644
--- a/src/qml/qml/qqmltypecompiler.cpp
+++ b/src/qml/qml/qqmltypecompiler.cpp
@@ -842,7 +842,7 @@ QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
if (targetObjectIndex == -1) {
*error = qQmlCompileError(
alias->referenceLocation,
- tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
+ QQmlComponentAndAliasResolverBase::tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
break;
}
@@ -872,7 +872,7 @@ QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
if (!targetCache) {
*error = qQmlCompileError(
alias->referenceLocation,
- tr("Invalid alias target location: %1").arg(property.toString()));
+ QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1").arg(property.toString()));
break;
}
@@ -909,7 +909,7 @@ QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
if (!targetProperty || targetProperty->coreIndex() > 0x0000FFFF) {
*error = qQmlCompileError(
alias->referenceLocation,
- tr("Invalid alias target location: %1").arg(property.toString()));
+ QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1").arg(property.toString()));
break;
}
@@ -937,7 +937,7 @@ QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
if (!isDeepAlias) {
*error = qQmlCompileError(
alias->referenceLocation,
- tr("Invalid alias target location: %1").arg(subProperty.toString()));
+ QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1").arg(subProperty.toString()));
break;
}
} else {
@@ -947,7 +947,7 @@ QQmlComponentAndAliasResolver<QQmlTypeCompiler>::resolveAliasesInObject(
if (valueTypeIndex == -1) {
*error = qQmlCompileError(
alias->referenceLocation,
- tr("Invalid alias target location: %1").arg(subProperty.toString()));
+ QQmlComponentAndAliasResolverBase::tr("Invalid alias target location: %1").arg(subProperty.toString()));
break;
}
Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp
index 9acd801672..7ff6a4fc94 100644
--- a/src/qml/qml/qqmltypedata.cpp
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -18,11 +18,10 @@
#include <memory>
-Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE)
-Q_LOGGING_CATEGORY(lcCycle, "qt.qml.typeresolution.cycle", QtWarningMsg)
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcCycle, "qt.qml.typeresolution.cycle", QtWarningMsg)
+
QQmlTypeData::TypeDataCallback::~TypeDataCallback()
{
}
@@ -208,7 +207,8 @@ QQmlComponentAndAliasResolver<QV4::CompiledData::CompilationUnit>::resolveAliase
const CompiledObject *obj = m_compiler->objectAt(objectIndex);
for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
if (!alias->hasFlag(QV4::CompiledData::Alias::Resolved)) {
- *error = qQmlCompileError( alias->referenceLocation, tr("Unresolved alias found"));
+ *error = qQmlCompileError(alias->referenceLocation,
+ QQmlComponentAndAliasResolverBase::tr("Unresolved alias found"));
return NoAliasResolved;
}
diff --git a/src/qml/qml/qqmltypedata_p.h b/src/qml/qml/qqmltypedata_p.h
index 97419b916b..436fef9b71 100644
--- a/src/qml/qml/qqmltypedata_p.h
+++ b/src/qml/qml/qqmltypedata_p.h
@@ -20,6 +20,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcCycle)
+
class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeData)
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 0d8786a9df..2ab81102c7 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -3,63 +3,122 @@
#include "qqmltypewrapper_p.h"
-#include <private/qqmlengine_p.h>
+#include <private/qjsvalue_p.h>
+
#include <private/qqmlcontext_p.h>
+#include <private/qqmlengine_p.h>
#include <private/qqmlmetaobject_p.h>
#include <private/qqmltypedata_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
-#include <private/qjsvalue_p.h>
-#include <private/qv4functionobject_p.h>
-#include <private/qv4objectproto_p.h>
-#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4identifiertable_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4objectproto_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4symbol_p.h>
QT_BEGIN_NAMESPACE
using namespace QV4;
DEFINE_OBJECT_VTABLE(QQmlTypeWrapper);
+DEFINE_OBJECT_VTABLE(QQmlTypeConstructor);
DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper);
void Heap::QQmlTypeWrapper::init(TypeNameMode m, QObject *o, const QQmlTypePrivate *type)
{
Q_ASSERT(type);
- Object::init();
- mode = m;
+ FunctionObject::init();
+ flags = quint8(m) | quint8(Type);
object.init(o);
- typePrivate = type;
- QQmlType::refHandle(typePrivate);
+ QQmlType::refHandle(type);
+ t.typePrivate = type;
}
void Heap::QQmlTypeWrapper::init(
TypeNameMode m, QObject *o, QQmlTypeNameCache *type, const QQmlImportRef *import)
{
Q_ASSERT(type);
- Object::init();
- mode = m;
+ FunctionObject::init();
+ flags = quint8(m) | quint8(Namespace);
object.init(o);
- typeNamespace = type;
- typeNamespace->addref();
- importNamespace = import;
+ n.typeNamespace = type;
+ n.typeNamespace->addref();
+ n.importNamespace = import;
}
void Heap::QQmlTypeWrapper::destroy()
{
- Q_ASSERT(typePrivate || typeNamespace);
- QQmlType::derefHandle(typePrivate);
- typePrivate = nullptr;
- if (typeNamespace)
- typeNamespace->release();
+ switch (kind()) {
+ case Type:
+ Q_ASSERT(t.typePrivate);
+ QQmlType::derefHandle(t.typePrivate);
+ delete[] t.constructors;
+ break;
+ case Namespace:
+ Q_ASSERT(n.typeNamespace);
+ n.typeNamespace->release();
+ break;
+ }
+
object.destroy();
- Object::destroy();
+ FunctionObject::destroy();
}
QQmlType Heap::QQmlTypeWrapper::type() const
{
- return QQmlType(typePrivate);
+ switch (kind()) {
+ case Type:
+ return QQmlType(t.typePrivate);
+ case Namespace:
+ return QQmlType();
+ }
+
+ Q_UNREACHABLE_RETURN(QQmlType());
+}
+
+QQmlTypeNameCache::Result Heap::QQmlTypeWrapper::queryNamespace(
+ const QV4::String *name, QQmlEnginePrivate *enginePrivate) const
+{
+ Q_ASSERT(kind() == Namespace);
+ Q_ASSERT(n.typeNamespace);
+ Q_ASSERT(n.importNamespace);
+ return n.typeNamespace->query(name, n.importNamespace, QQmlTypeLoader::get(enginePrivate));
+
+}
+
+template<typename Callback>
+void warnWithLocation(const Heap::QQmlTypeWrapper *wrapper, Callback &&callback)
+{
+ auto log = qWarning().noquote().nospace();
+ if (const CppStackFrame *frame = wrapper->internalClass->engine->currentStackFrame)
+ log << frame->source() << ':' << frame->lineNumber() << ':';
+ callback(log.space());
+}
+
+void Heap::QQmlTypeWrapper::warnIfUncreatable() const
+{
+ const QQmlType t = type();
+ Q_ASSERT(t.isValid());
+
+ if (t.isValueType())
+ return;
+
+ if (t.isSingleton()) {
+ warnWithLocation(this, [&](QDebug &log) {
+ log << "You are calling a Q_INVOKABLE constructor of" << t.typeName()
+ << "which is a singleton in QML.";
+ });
+ return;
+ }
+
+ if (!t.isCreatable()) {
+ warnWithLocation(this, [&](QDebug &log) {
+ log << "You are calling a Q_INVOKABLE constructor of" << t.typeName()
+ << "which is uncreatable in QML.";
+ });
+ }
}
bool QQmlTypeWrapper::isSingleton() const
@@ -136,17 +195,59 @@ QVariant QQmlTypeWrapper::toVariant() const
return QVariant::fromValue<QObject*>(e->singletonInstance<QObject*>(type));
}
+ReturnedValue QQmlTypeWrapper::method_hasInstance(
+ const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
+{
+ // we want to immediately call instanceOf rather than going through Function
+
+ if (!argc)
+ return Encode(false);
+ if (const Object *o = thisObject->as<Object>())
+ return o->instanceOf(argv[0]);
+ return Encode(false);
+}
+
+ReturnedValue QQmlTypeWrapper::method_toString(
+ const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ const QQmlTypeWrapper *typeWrapper = thisObject->as<QQmlTypeWrapper>();
+ if (!typeWrapper)
+ RETURN_UNDEFINED();
+
+ const QString name = typeWrapper->d()->type().qmlTypeName();
+ return Encode(b->engine()->newString(name.isEmpty()
+ ? QLatin1String("Unknown Type")
+ : name));
+}
+
+void QQmlTypeWrapper::initProto(ExecutionEngine *v4)
+{
+ if (v4->typeWrapperPrototype()->d_unchecked())
+ return;
+
+ Scope scope(v4);
+ ScopedObject o(scope, v4->newObject());
+
+ o->defineDefaultProperty(v4->symbol_hasInstance(), method_hasInstance, 1, Attr_ReadOnly);
+ o->defineDefaultProperty(v4->id_toString(), method_toString, 0);
+ o->setPrototypeOf(v4->functionPrototype());
+
+ v4->jsObjects[QV4::ExecutionEngine::TypeWrapperProto] = o->d();
+}
// Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t,
Heap::QQmlTypeWrapper::TypeNameMode mode)
{
Q_ASSERT(t.isValid());
- Scope scope(engine);
+ initProto(engine);
- Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>(
- mode, o, t.priv()));
- return w.asReturnedValue();
+ QV4::MemoryManager *mm = engine->memoryManager;
+
+ if (const QMetaObject *mo = t.metaObject(); !mo || mo->constructorCount() == 0)
+ return mm->allocate<QQmlTypeWrapper>(mode, o, t.priv())->asReturnedValue();
+
+ return mm->allocate<QQmlTypeConstructor>(mode, o, t.priv())->asReturnedValue();
}
// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
@@ -157,6 +258,8 @@ ReturnedValue QQmlTypeWrapper::create(
{
Q_ASSERT(t);
Q_ASSERT(importNamespace);
+ initProto(engine);
+
Scope scope(engine);
Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>(
@@ -203,7 +306,8 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
if (QObject *qobjectSingleton = enginePrivate->singletonInstance<QObject*>(type)) {
// check for enum value
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ const bool includeEnums
+ = w->d()->typeNameMode() == Heap::QQmlTypeWrapper::IncludeEnums;
if (includeEnums && name->startsWithUpper()) {
bool ok = false;
int value = enumForSingleton(v4, name, type, &ok);
@@ -278,14 +382,11 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
// Fall through to base implementation
- } else if (w->d()->typeNamespace) {
- Q_ASSERT(w->d()->importNamespace);
- QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(
- name, w->d()->importNamespace, QQmlTypeLoader::get(enginePrivate));
-
+ } else if (w->d()->kind() == Heap::QQmlTypeWrapper::Namespace) {
+ const QQmlTypeNameCache::Result r = w->d()->queryNamespace(name, enginePrivate);
if (r.isValid()) {
if (r.type.isValid()) {
- return create(scope.engine, object, r.type, w->d()->mode);
+ return create(scope.engine, object, r.type, w->d()->typeNameMode());
} else if (r.scriptIndex != -1) {
QV4::ScopedObject scripts(scope, context->importedScripts().valueRef());
return scripts->get(r.scriptIndex);
@@ -389,15 +490,16 @@ bool QQmlTypeWrapper::virtualIsEqualTo(Managed *a, Managed *b)
return false;
}
-static ReturnedValue instanceOfQObject(const QV4::QQmlTypeWrapper *typeWrapper, const QObjectWrapper *objectWrapper)
+static ReturnedValue instanceOfQObject(
+ const QV4::QQmlTypeWrapper *typeWrapper, QObject *wrapperObject)
{
QV4::ExecutionEngine *engine = typeWrapper->internalClass()->engine;
// in case the wrapper outlived the QObject*
- const QObject *wrapperObject = objectWrapper->object();
if (!wrapperObject)
return engine->throwTypeError();
- const QMetaType myTypeId = typeWrapper->d()->type().typeId();
+ const QQmlType type = typeWrapper->d()->type();
+ const QMetaType myTypeId = type.typeId();
QQmlMetaObject myQmlType;
if (!myTypeId.isValid()) {
// we're a composite type; a composite type cannot be equal to a
@@ -422,7 +524,12 @@ static ReturnedValue instanceOfQObject(const QV4::QQmlTypeWrapper *typeWrapper,
const QMetaObject *theirType = wrapperObject->metaObject();
- return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType));
+ if (QQmlMetaObject::canConvert(theirType, myQmlType))
+ return Encode(true);
+ else if (type.isValueType())
+ return Encode::undefined();
+ else
+ return Encode(false);
}
ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const Value &var)
@@ -431,21 +538,46 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject);
if (const QObjectWrapper *objectWrapper = var.as<QObjectWrapper>())
- return instanceOfQObject(typeWrapper, objectWrapper);
+ return instanceOfQObject(typeWrapper, objectWrapper->object());
+
+ if (const QQmlTypeWrapper *varTypeWrapper = var.as<QQmlTypeWrapper>()) {
+ // Singleton or attachment
+ if (QObject *varObject = varTypeWrapper->object())
+ return instanceOfQObject(typeWrapper, varObject);
+ }
const QQmlType type = typeWrapper->d()->type();
- if (type.isValueType()) {
+
+ // If the target type is an object type we want null.
+ if (!type.isValueType())
+ return Encode(false);
+
+ const auto canCastValueType = [&]() -> bool {
if (const QQmlValueTypeWrapper *valueWrapper = var.as<QQmlValueTypeWrapper>()) {
- return QV4::Encode(QQmlMetaObject::canConvert(valueWrapper->metaObject(),
- type.metaObjectForValueType()));
+ return QQmlMetaObject::canConvert(
+ valueWrapper->metaObject(), type.metaObjectForValueType());
}
- // We want "foo as valuetype" to return undefined if it doesn't match.
- return Encode::undefined();
- }
+ switch (type.typeId().id()) {
+ case QMetaType::Void:
+ return var.isUndefined();
+ case QMetaType::QVariant:
+ return true; // Everything is a var
+ case QMetaType::Int:
+ return var.isInteger();
+ case QMetaType::Double:
+ return var.isDouble(); // Integers are also doubles
+ case QMetaType::QString:
+ return var.isString();
+ case QMetaType::Bool:
+ return var.isBoolean();
+ }
- // If the target type is an object type we want null.
- return Encode(false);
+ return false;
+ };
+
+ // We want "foo as valuetype" to return undefined if it doesn't match.
+ return canCastValueType() ? Encode(true) : Encode::undefined();
}
ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
@@ -469,7 +601,8 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ const bool includeEnums
+ = w->d()->typeNameMode() == Heap::QQmlTypeWrapper::IncludeEnums;
if (!includeEnums || !name->startsWithUpper()) {
QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
if (ddata && ddata->propertyCache) {
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 717efaf20e..fa859dd118 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -19,7 +19,8 @@
#include <QtCore/qpointer.h>
#include <private/qv4value_p.h>
-#include <private/qv4object_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4qmetaobjectwrapper_p.h>
QT_BEGIN_NAMESPACE
@@ -32,26 +33,65 @@ namespace QV4 {
namespace Heap {
-struct QQmlTypeWrapper : Object {
- enum TypeNameMode {
- IncludeEnums,
- ExcludeEnums
+struct QQmlTypeWrapper : FunctionObject {
+
+ enum TypeNameMode : quint8 {
+ ExcludeEnums = 0x0,
+ IncludeEnums = 0x1,
+ TypeNameModeMask = 0x1,
+ };
+
+ enum Kind : quint8 {
+ Type = 0x0,
+ Namespace = 0x2,
+ KindMask = 0x2
};
void init(TypeNameMode m, QObject *o, const QQmlTypePrivate *type);
void init(TypeNameMode m, QObject *o, QQmlTypeNameCache *type, const QQmlImportRef *import);
void destroy();
- TypeNameMode mode;
- QV4QPointer<QObject> object;
+
+ const QMetaObject *metaObject() const { return type().metaObject(); }
+ QMetaType metaType() const { return type().typeId(); }
QQmlType type() const;
+ TypeNameMode typeNameMode() const { return TypeNameMode(flags & TypeNameModeMask); }
+ Kind kind() const { return Kind(flags & KindMask); }
+
+ const QQmlPropertyData *ensureConstructorsCache(
+ const QMetaObject *metaObject, QMetaType metaType)
+ {
+ Q_ASSERT(kind() == Type);
+ if (!t.constructors && metaObject) {
+ t.constructors = QMetaObjectWrapper::createConstructors(metaObject, metaType);
+ warnIfUncreatable();
+ }
+ return t.constructors;
+ }
+ void warnIfUncreatable() const;
+
+ QQmlTypeNameCache::Result queryNamespace(
+ const QV4::String *name, QQmlEnginePrivate *enginePrivate) const;
- const QQmlTypePrivate *typePrivate;
- QQmlTypeNameCache *typeNamespace;
- const QQmlImportRef *importNamespace;
+ QV4QPointer<QObject> object;
+
+ union {
+ struct {
+ const QQmlTypePrivate *typePrivate;
+ const QQmlPropertyData *constructors;
+ } t;
+ struct {
+ QQmlTypeNameCache *typeNamespace;
+ const QQmlImportRef *importNamespace;
+ } n;
+ };
+
+ quint8 flags;
};
+using QQmlTypeConstructor = QQmlTypeWrapper;
+
struct QQmlScopedEnumWrapper : Object {
void init() { Object::init(); }
void destroy();
@@ -62,9 +102,10 @@ struct QQmlScopedEnumWrapper : Object {
}
-struct Q_QML_EXPORT QQmlTypeWrapper : Object
+struct Q_QML_EXPORT QQmlTypeWrapper : FunctionObject
{
- V4_OBJECT2(QQmlTypeWrapper, Object)
+ V4_OBJECT2(QQmlTypeWrapper, FunctionObject)
+ V4_PROTOTYPE(typeWrapperPrototype)
V4_NEEDS_DESTROY
bool isSingleton() const;
@@ -74,6 +115,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
QVariant toVariant() const;
+ static void initProto(ExecutionEngine *v4);
+
static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlType &,
Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums);
static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlRefPointer<QQmlTypeNameCache> &, const QQmlImportRef *,
@@ -95,6 +138,25 @@ protected:
static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p);
static bool virtualIsEqualTo(Managed *that, Managed *o);
static ReturnedValue virtualInstanceOf(const Object *typeObject, const Value &var);
+
+private:
+ static ReturnedValue method_hasInstance(
+ const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_toString(
+ const FunctionObject *b, const Value *thisObject, const Value *, int);
+};
+
+struct QQmlTypeConstructor : QQmlTypeWrapper
+{
+ V4_OBJECT2(QQmlTypeConstructor, QQmlTypeWrapper)
+
+ static ReturnedValue virtualCallAsConstructor(
+ const FunctionObject *f, const Value *argv, int argc, const Value *)
+ {
+ Q_ASSERT(f->as<QQmlTypeWrapper>());
+ return QMetaObjectWrapper::construct(
+ static_cast<const QQmlTypeWrapper *>(f)->d(), argv, argc);
+ }
};
struct Q_QML_EXPORT QQmlScopedEnumWrapper : Object
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 8815c914ce..dd23547c04 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -111,12 +111,11 @@ struct Q_QML_EXPORT QQmlPointFValueType
Q_GADGET
QML_VALUE_TYPE(point)
QML_FOREIGN(QPointF)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlPointFValueType)
QML_STRUCTURED_VALUE
public:
- QQmlPointFValueType() = default;
+ Q_INVOKABLE QQmlPointFValueType() = default;
Q_INVOKABLE QQmlPointFValueType(const QPoint &point) : v(point) {}
Q_INVOKABLE QString toString() const;
qreal x() const;
@@ -135,7 +134,6 @@ struct Q_QML_EXPORT QQmlPointValueType
Q_GADGET
QML_ANONYMOUS
QML_FOREIGN(QPoint)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlPointValueType)
QML_STRUCTURED_VALUE
@@ -159,12 +157,11 @@ struct Q_QML_EXPORT QQmlSizeFValueType
Q_GADGET
QML_VALUE_TYPE(size)
QML_FOREIGN(QSizeF)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlSizeFValueType)
QML_STRUCTURED_VALUE
public:
- QQmlSizeFValueType() = default;
+ Q_INVOKABLE QQmlSizeFValueType() = default;
Q_INVOKABLE QQmlSizeFValueType(const QSize &size) : v(size) {}
Q_INVOKABLE QString toString() const;
qreal width() const;
@@ -183,7 +180,6 @@ struct Q_QML_EXPORT QQmlSizeValueType
Q_GADGET
QML_ANONYMOUS
QML_FOREIGN(QSize)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlSizeValueType)
QML_STRUCTURED_VALUE
@@ -213,12 +209,11 @@ struct Q_QML_EXPORT QQmlRectFValueType
Q_GADGET
QML_VALUE_TYPE(rect)
QML_FOREIGN(QRectF)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlRectFValueType)
QML_STRUCTURED_VALUE
public:
- QQmlRectFValueType() = default;
+ Q_INVOKABLE QQmlRectFValueType() = default;
Q_INVOKABLE QQmlRectFValueType(const QRect &rect) : v(rect) {}
Q_INVOKABLE QString toString() const;
qreal x() const;
@@ -253,7 +248,6 @@ struct Q_QML_EXPORT QQmlRectValueType
Q_GADGET
QML_ANONYMOUS
QML_FOREIGN(QRect)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlRectValueType)
QML_STRUCTURED_VALUE
@@ -284,7 +278,6 @@ namespace QQmlEasingEnums
{
Q_NAMESPACE_EXPORT(Q_QML_EXPORT)
QML_NAMED_ELEMENT(Easing)
-QML_ADDED_IN_VERSION(2, 0)
enum Type {
Linear = QEasingCurve::Linear,
@@ -323,7 +316,6 @@ struct Q_QML_EXPORT QQmlEasingValueType
Q_GADGET
QML_ANONYMOUS
QML_FOREIGN(QEasingCurve)
- QML_ADDED_IN_VERSION(2, 0)
QML_EXTENDED(QQmlEasingValueType)
QML_STRUCTURED_VALUE
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 7075d0f5f6..21c5a76dd8 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -3,42 +3,33 @@
#include "qqmlvaluetypewrapper_p.h"
-#include <private/qqmlvaluetype_p.h>
#include <private/qqmlbinding_p.h>
-#include <private/qqmlglobal_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmlvaluetype_p.h>
-#include <private/qv4engine_p.h>
-#include <private/qv4functionobject_p.h>
-#include <private/qv4variantobject_p.h>
#include <private/qv4alloca_p.h>
-#include <private/qv4stackframe_p.h>
-#include <private/qv4objectiterator_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-#include <private/qv4identifiertable_p.h>
-#include <private/qv4lookup_p.h>
-#include <private/qv4sequenceobject_p.h>
#include <private/qv4arraybuffer_p.h>
#include <private/qv4dateobject_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4identifiertable_p.h>
#include <private/qv4jsonobject_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4stackframe_p.h>
+#include <private/qv4variantobject_p.h>
+
+#include <QtCore/qline.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qloggingcategory.h>
+
#if QT_CONFIG(regularexpression)
#include <private/qv4regexpobject_p.h>
#endif
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
-#endif
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/QLine>
-#include <QtCore/QLineF>
-#include <QtCore/QSize>
-#include <QtCore/QSizeF>
-#include <QtCore/QTimeZone>
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
-
DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeWrapper);
namespace QV4 {
@@ -304,7 +295,7 @@ static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
{
if (isFunction) {
// calling a Q_INVOKABLE function of a value type
- return QV4::QObjectMethod::create(engine->rootContext(), valueTypeWrapper, coreIndex);
+ return QV4::QObjectMethod::create(engine, valueTypeWrapper, coreIndex);
}
const QMetaObject *metaObject = valueTypeWrapper->metaObject();
@@ -785,7 +776,7 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
- QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
+ QV4::Scoped<JavaScriptFunctionObject> f(scope, bindingFunction->bindingFunction());
QV4::ScopedContext ctx(scope, f->scope());
QQmlBinding *newBinding = QQmlBinding::create(&cacheData, f->function(), referenceObject, context, ctx);
newBinding->setSourceLocation(bindingFunction->currentLocation());
@@ -796,12 +787,12 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
QQmlPropertyPrivate::setBinding(newBinding);
return true;
} else if (referenceObject) {
- if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (Q_UNLIKELY(lcBuiltinsBindingRemoval().isInfoEnabled())) {
if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd.coreIndex()))) {
Q_ASSERT(binding->kind() == QQmlAbstractBinding::QmlBinding);
const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
const auto stackFrame = v4->currentStackFrame;
- qCInfo(lcBindingRemoval,
+ qCInfo(lcBuiltinsBindingRemoval,
"Overwriting binding on %s::%s which was initially bound at %s by setting \"%s\" at %s:%d",
referenceObject->metaObject()->className(), referenceObject->metaObject()->property(referencePropertyIndex).name(),
qPrintable(qmlBinding->expressionIdentifier()),
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index 5b3894a07f..97709dfb4c 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -19,14 +19,6 @@
#include <private/qtqmlglobal_p.h>
#include <private/qv4referenceobject_p.h>
-#include <private/qqmlpropertycache_p.h>
-#include <private/qqmltype_p_p.h>
-#include <private/qqmltypewrapper_p.h>
-#include <private/qv4object_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-#include <private/qv4sequenceobject_p.h>
-#include <private/qv4value_p.h>
-#include <private/qv4referenceobject_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 5f3b6975ca..dffddd2e0d 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -1141,7 +1141,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
QV4::Scope scope(v4);
- QV4::ScopedFunctionObject function(scope, method(id));
+ QV4::Scoped<QV4::JavaScriptFunctionObject> function(scope, method(id));
if (!function) {
// The function was not compiled. There are some exceptional cases which the
// expression rewriter does not rewrite properly (e.g., \r-terminated lines
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index c5d18860db..b4800584a3 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1708,7 +1708,7 @@ DEFINE_OBJECT_VTABLE(QQmlXMLHttpRequestWrapper);
void Heap::QQmlXMLHttpRequestCtor::init(ExecutionEngine *engine)
{
- Heap::FunctionObject::init(engine->rootContext(), QStringLiteral("XMLHttpRequest"));
+ Heap::FunctionObject::init(engine, QStringLiteral("XMLHttpRequest"));
Scope scope(engine);
Scoped<QV4::QQmlXMLHttpRequestCtor> ctor(scope, this);
diff --git a/src/qml/qqmlbuiltins_p.h b/src/qml/qqmlbuiltins_p.h
index 187e11d5da..338bcf68a9 100644
--- a/src/qml/qqmlbuiltins_p.h
+++ b/src/qml/qqmlbuiltins_p.h
@@ -15,10 +15,8 @@
// We mean it.
//
-// QmlBuiltins does not link QtQml - rather the other way around. Still, we can use the QtQml
-// headers here. This works because we explicitly include the QtQml include directories in the
-// manual moc call.
#include <private/qqmlcomponentattached_p.h>
+
#include <QtQml/qjsvalue.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlscriptstring.h>
@@ -36,6 +34,8 @@
#include <QtCore/qtypes.h>
#include <QtCore/qchar.h>
#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
+#include <QtCore/qjsonarray.h>
#include <climits>
@@ -120,14 +120,24 @@ struct QQmlIntForeign
QML_VALUE_TYPE(int)
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(int)
- QML_PRIMITIVE_ALIAS(qint32)
- QML_PRIMITIVE_ALIAS(int32_t)
#ifdef QML_SIZE_IS_32BIT
+ // Keep qsizetype as primitive alias. We want it as separate type.
QML_PRIMITIVE_ALIAS(qsizetype)
#endif
-#ifdef QML_LONG_IS_32BIT
- QML_PRIMITIVE_ALIAS(long)
-#endif
+};
+
+struct QQmlQint32Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(qint32)
+ QML_USING(int)
+};
+
+struct QQmlInt32TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(int32_t)
+ QML_USING(int)
};
struct QQmlDoubleForeign
@@ -137,9 +147,6 @@ struct QQmlDoubleForeign
QML_VALUE_TYPE(double)
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(double)
-#if !defined(QT_COORD_TYPE) || defined(QT_COORD_TYPE_IS_DOUBLE)
- QML_PRIMITIVE_ALIAS(qreal)
-#endif
};
struct QQmlStringForeign
@@ -214,10 +221,13 @@ struct QQmlQint8Foreign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(qint8)
- QML_PRIMITIVE_ALIAS(int8_t)
-#if CHAR_MAX == SCHAR_MAX
- QML_PRIMITIVE_ALIAS(char)
-#endif
+};
+
+struct QQmlInt8TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(int8_t)
+ QML_USING(qint8)
};
struct QQmlQuint8Foreign
@@ -226,10 +236,32 @@ struct QQmlQuint8Foreign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(quint8)
- QML_PRIMITIVE_ALIAS(uint8_t)
- QML_PRIMITIVE_ALIAS(uchar)
+};
+
+struct QQmlUint8TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(uint8_t)
+ QML_USING(quint8)
+};
+
+struct QQmlUcharForeign
+{
+ Q_GADGET
+ QML_FOREIGN(uchar)
+ QML_USING(quint8)
+};
+
+struct QQmlCharForeign
+{
+ Q_GADGET
+ QML_FOREIGN(char)
#if CHAR_MAX == UCHAR_MAX
- QML_PRIMITIVE_ALIAS(char)
+ QML_USING(quint8)
+#elif CHAR_MAX == SCHAR_MAX
+ QML_USING(qint8)
+#else
+# error char is neither quint8 nor qint8
#endif
};
@@ -239,8 +271,20 @@ struct QQmlShortForeign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(short)
- QML_PRIMITIVE_ALIAS(qint16)
- QML_PRIMITIVE_ALIAS(int16_t)
+};
+
+struct QQmlQint16Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(qint16)
+ QML_USING(short)
+};
+
+struct QQmlInt16TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(int16_t)
+ QML_USING(short)
};
struct QQmlUshortForeign
@@ -249,8 +293,20 @@ struct QQmlUshortForeign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(ushort)
- QML_PRIMITIVE_ALIAS(quint16)
- QML_PRIMITIVE_ALIAS(uint16_t)
+};
+
+struct QQmlQuint16Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(quint16)
+ QML_USING(ushort)
+};
+
+struct QQmlUint16TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(uint16_t)
+ QML_USING(ushort)
};
struct QQmlUintForeign
@@ -259,11 +315,20 @@ struct QQmlUintForeign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(uint)
- QML_PRIMITIVE_ALIAS(quint32)
- QML_PRIMITIVE_ALIAS(uint32_t)
-#ifdef QML_LONG_IS_32BIT
- QML_PRIMITIVE_ALIAS(ulong)
-#endif
+};
+
+struct QQmlQuint32Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(quint32)
+ QML_USING(uint)
+};
+
+struct QQmlUint32TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(uint32_t)
+ QML_USING(uint)
};
struct QQmlQlonglongForeign
@@ -272,26 +337,71 @@ struct QQmlQlonglongForeign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(qlonglong)
- QML_PRIMITIVE_ALIAS(qint64)
- QML_PRIMITIVE_ALIAS(int64_t)
-#ifdef QML_LONG_IS_64BIT
- QML_PRIMITIVE_ALIAS(long)
-#endif
#ifdef QML_SIZE_IS_64BIT
+ // Keep qsizetype as primitive alias. We want it as separate type.
QML_PRIMITIVE_ALIAS(qsizetype)
#endif
};
+struct QQmlQint64Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(qint64)
+ QML_USING(qlonglong)
+};
+
+struct QQmlInt64TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(int64_t)
+ QML_USING(qlonglong)
+};
+
+struct QQmlLongForeign
+{
+ Q_GADGET
+ QML_FOREIGN(long)
+#if defined QML_LONG_IS_32BIT
+ QML_USING(int)
+#elif defined QML_LONG_IS_64BIT
+ QML_USING(qlonglong)
+#else
+# error long is neither 32bit nor 64bit
+#endif
+};
+
struct QQmlQulonglongForeign
{
Q_GADGET
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(qulonglong)
- QML_PRIMITIVE_ALIAS(quint64)
- QML_PRIMITIVE_ALIAS(uint64_t)
-#ifdef QML_LONG_IS_64BIT
- QML_PRIMITIVE_ALIAS(ulong)
+};
+
+struct QQmlQuint64Foreign
+{
+ Q_GADGET
+ QML_FOREIGN(quint64)
+ QML_USING(qulonglong)
+};
+
+struct QQmlUint64TForeign
+{
+ Q_GADGET
+ QML_FOREIGN(uint64_t)
+ QML_USING(qulonglong)
+};
+
+struct QQmlUlongForeign
+{
+ Q_GADGET
+ QML_FOREIGN(ulong)
+#if defined QML_LONG_IS_32BIT
+ QML_USING(uint)
+#elif defined QML_LONG_IS_64BIT
+ QML_USING(qulonglong)
+#else
+# error ulong is neither 32bit nor 64bit
#endif
};
@@ -301,8 +411,18 @@ struct QQmlFloatForeign
QML_ANONYMOUS
QML_EXTENDED_JAVASCRIPT(Number)
QML_FOREIGN(float)
-#if defined(QT_COORD_TYPE) && defined(QT_COORD_TYPE_IS_FLOAT)
- QML_PRIMITIVE_ALIAS(qreal)
+};
+
+struct QQmlQRealForeign
+{
+ Q_GADGET
+ QML_FOREIGN(qreal)
+#if !defined(QT_COORD_TYPE) || defined(QT_COORD_TYPE_IS_DOUBLE)
+ QML_USING(double)
+#elif defined(QT_COORD_TYPE_IS_FLOAT)
+ QML_USING(float)
+#else
+# error qreal is neither float nor double
#endif
};
@@ -338,6 +458,14 @@ struct QQmlQByteArrayForeign
QML_FOREIGN(QByteArray)
};
+struct QQmlQByteArrayListForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QByteArrayList)
+ QML_SEQUENTIAL_CONTAINER(QByteArray)
+};
+
struct QQmlQStringListForeign
{
Q_GADGET
@@ -360,7 +488,13 @@ struct QQmlQObjectListForeign
QML_ANONYMOUS
QML_FOREIGN(QObjectList)
QML_SEQUENTIAL_CONTAINER(QObject*)
- QML_PRIMITIVE_ALIAS(QList<QObject*>)
+};
+
+struct QQmlQListQObjectForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QList<QObject*>)
+ QML_USING(QObjectList)
};
struct QQmlQJSValueForeign
@@ -402,6 +536,22 @@ struct QQmlQJsonObjectForeign
QML_EXTENDED_JAVASCRIPT(Object)
};
+struct QQmlQJsonValueForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QJsonValue)
+ QML_EXTENDED_JAVASCRIPT(Object)
+};
+
+struct QQmlQJsonArrayForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QJsonArray)
+ QML_SEQUENTIAL_CONTAINER(QJsonValue)
+};
+
QT_END_NAMESPACE
#endif // QQMLBUILTINS_H
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index bc06d4ed51..6991d642f5 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -30,7 +30,7 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
+Q_STATIC_LOGGING_CATEGORY(lcQtQmlBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
enum class QQmlBindEntryKind: quint8 {
V4Value,
@@ -686,7 +686,7 @@ void QQmlBind::setTarget(const QQmlProperty &p)
void QQmlBindEntry::setTarget(QQmlBind *q, const QQmlProperty &p)
{
- if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (Q_UNLIKELY(lcQtQmlBindingRemoval().isInfoEnabled())) {
if (QObject *oldObject = prop.object()) {
QMetaProperty metaProp = oldObject->metaObject()->property(prop.index());
if (metaProp.hasNotifySignal()) {
@@ -1126,7 +1126,7 @@ void QQmlBind::targetValueChanged()
line = ddata->lineNumber;
}
- qCInfo(lcBindingRemoval,
+ qCInfo(lcQtQmlBindingRemoval,
"The target property of the Binding element created at %s:%d was changed from "
"elsewhere. This does not overwrite the binding. The target property will still be "
"updated when the value of the Binding element changes.",
diff --git a/src/qml/types/qqmlbind_p.h b/src/qml/types/qqmlbind_p.h
index aaefbc0618..d4c93ebe0a 100644
--- a/src/qml/types/qqmlbind_p.h
+++ b/src/qml/types/qqmlbind_p.h
@@ -15,7 +15,7 @@
// We mean it.
//
-#include <private/qtqmlglobal_p.h>
+#include <QtQmlMeta/qtqmlmetaexports.h>
#include <QtQml/qqml.h>
#include <QtCore/qobject.h>
@@ -23,7 +23,7 @@
QT_BEGIN_NAMESPACE
class QQmlBindPrivate;
-class Q_QML_EXPORT QQmlBind : public QObject, public QQmlPropertyValueSource, public QQmlParserStatus
+class Q_QMLMETA_EXPORT QQmlBind : public QObject, public QQmlPropertyValueSource, public QQmlParserStatus
{
public:
enum RestorationMode {
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 19363f9f76..710adc3efa 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -23,7 +23,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQmlConnections, "qt.qml.connections")
+Q_STATIC_LOGGING_CATEGORY(lcQmlConnections, "qt.qml.connections")
// This is the equivalent of QQmlBoundSignal for C++ methods as as slots.
// If a type derived from QQmlConnnections is compiled using qmltc, the
@@ -415,13 +415,12 @@ void QQmlConnections::connectSignalsToMethods()
auto *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
signal->setEnabled(d->enabled);
- QV4::ScopedFunctionObject method(
+ QV4::Scoped<QV4::JavaScriptFunctionObject> method(
scope, vmeMetaObject->vmeMethod(handler->coreIndex()));
QQmlBoundSignalExpression *expression = ctxtdata
? new QQmlBoundSignalExpression(
- target, signalIndex, ctxtdata, this,
- method->as<QV4::FunctionObject>()->function())
+ target, signalIndex, ctxtdata, this, method->function())
: nullptr;
signal->takeExpression(expression);
diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h
index e0100aa452..f0852cda73 100644
--- a/src/qml/types/qqmlconnections_p.h
+++ b/src/qml/types/qqmlconnections_p.h
@@ -15,9 +15,11 @@
// We mean it.
//
-#include <qqml.h>
#include <private/qqmlcustomparser_p.h>
+#include <QtQmlMeta/qtqmlmetaexports.h>
+#include <QtQml/qqml.h>
+
#include <QtCore/qobject.h>
#include <QtCore/qstring.h>
@@ -26,7 +28,7 @@ QT_BEGIN_NAMESPACE
class QQmlBoundSignal;
class QQmlContext;
class QQmlConnectionsPrivate;
-class Q_QML_EXPORT QQmlConnections : public QObject, public QQmlParserStatus
+class Q_QMLMETA_EXPORT QQmlConnections : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlConnections)
diff --git a/src/qml/types/qqmllocaleenums_p.h b/src/qml/types/qqmllocaleenums_p.h
new file mode 100644
index 0000000000..771b74e5fb
--- /dev/null
+++ b/src/qml/types/qqmllocaleenums_p.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLLOCALEENUMS_H
+#define QQMLLOCALEENUMS_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/qtqmlglobal_p.h>
+#include <private/qqmllocale_p.h>
+
+#include <QtQmlMeta/qtqmlmetaexports.h>
+#include <QtQml/qqml.h>
+
+QT_REQUIRE_CONFIG(qml_locale);
+
+QT_BEGIN_NAMESPACE
+
+// Derive again so that we don't expose QQmlLocale as two different QML types
+// as that would be bad style.
+struct Q_QMLMETA_EXPORT QQmlLocaleEnums : public QQmlLocale
+{
+ Q_GADGET
+};
+
+// Use QML_FOREIGN_NAMESPACE so that we can expose QQmlLocaleEnums as a namespace
+// rather than a value type.
+namespace QQmlLocaleEnumsForeign
+{
+Q_NAMESPACE_EXPORT(Q_QMLMETA_EXPORT)
+QML_NAMED_ELEMENT(Locale)
+QML_ADDED_IN_VERSION(2, 2)
+QML_FOREIGN_NAMESPACE(QQmlLocaleEnums)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLLOCALEENUMS_H
+
diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/types/qqmlloggingcategory.cpp
index 8d7fd6c04d..c18be74525 100644
--- a/src/qml/qml/qqmlloggingcategory.cpp
+++ b/src/qml/types/qqmlloggingcategory.cpp
@@ -83,7 +83,7 @@
*/
QQmlLoggingCategory::QQmlLoggingCategory(QObject *parent)
- : QObject(parent)
+ : QQmlLoggingCategoryBase(parent)
, m_initialized(false)
{
}
@@ -102,11 +102,6 @@ QQmlLoggingCategory::DefaultLogLevel QQmlLoggingCategory::defaultLogLevel() cons
return m_defaultLogLevel;
}
-QLoggingCategory *QQmlLoggingCategory::category() const
-{
- return m_category.get();
-}
-
void QQmlLoggingCategory::classBegin()
{
}
@@ -114,12 +109,10 @@ void QQmlLoggingCategory::classBegin()
void QQmlLoggingCategory::componentComplete()
{
m_initialized = true;
- if (m_name.isNull()) {
+ if (m_name.isNull())
qmlWarning(this) << QLatin1String("Declaring the name of a LoggingCategory is mandatory and cannot be changed later");
- } else {
- auto category = std::make_unique<QLoggingCategory>(m_name.constData(), QtMsgType(m_defaultLogLevel));
- m_category.swap(category);
- }
+ else
+ setCategory(m_name.constData(), QtMsgType(m_defaultLogLevel));
}
void QQmlLoggingCategory::setDefaultLogLevel(DefaultLogLevel defaultLogLevel)
diff --git a/src/qml/qml/qqmlloggingcategory_p.h b/src/qml/types/qqmlloggingcategory_p.h
index 4a27e7e1d7..1f1f9abb63 100644
--- a/src/qml/qml/qqmlloggingcategory_p.h
+++ b/src/qml/types/qqmlloggingcategory_p.h
@@ -15,19 +15,21 @@
// We mean it.
//
-#include <QtCore/qobject.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qloggingcategory.h>
+#include <private/qqmlloggingcategorybase_p.h>
+
+#include <QtQmlMeta/qtqmlmetaexports.h>
-#include <QtQml/qqmlparserstatus.h>
#include <QtQml/qqml.h>
-#include <QtCore/private/qglobal_p.h>
+#include <QtQml/qqmlparserstatus.h>
-#include <memory>
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
-class QQmlLoggingCategory : public QObject, public QQmlParserStatus
+class Q_QMLMETA_EXPORT QQmlLoggingCategory : public QQmlLoggingCategoryBase, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
@@ -55,14 +57,11 @@ public:
QString name() const;
void setName(const QString &name);
- QLoggingCategory *category() const;
-
void classBegin() override;
void componentComplete() override;
private:
QByteArray m_name;
- std::unique_ptr<QLoggingCategory> m_category;
DefaultLogLevel m_defaultLogLevel = Debug;
bool m_initialized;
};
diff --git a/src/qml/types/qqmltimer_p.h b/src/qml/types/qqmltimer_p.h
index e75b8bbe9d..f926262952 100644
--- a/src/qml/types/qqmltimer_p.h
+++ b/src/qml/types/qqmltimer_p.h
@@ -15,18 +15,18 @@
// We mean it.
//
-#include <qqml.h>
+#include <private/qtqmlglobal_p.h>
+#include <QtQmlMeta/qtqmlmetaexports.h>
+#include <QtQml/qqml.h>
#include <QtCore/qobject.h>
-#include <private/qtqmlglobal_p.h>
-
QT_REQUIRE_CONFIG(qml_animation);
QT_BEGIN_NAMESPACE
class QQmlTimerPrivate;
-class Q_QML_EXPORT QQmlTimer : public QObject, public QQmlParserStatus
+class Q_QMLMETA_EXPORT QQmlTimer : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQmlTimer)
diff --git a/src/qmlcompiler/CMakeLists.txt b/src/qmlcompiler/CMakeLists.txt
index 4e7d1cbf1c..00470cebc1 100644
--- a/src/qmlcompiler/CMakeLists.txt
+++ b/src/qmlcompiler/CMakeLists.txt
@@ -6,44 +6,46 @@
#####################################################################
qt_internal_add_module(QmlCompiler
- GENERATE_CPP_EXPORTS
PLUGIN_TYPES qmllint
SOURCES
- qcoloroutput_p.h qcoloroutput.cpp
+ qcoloroutput.cpp qcoloroutput_p.h
qdeferredpointer_p.h
qqmljsannotation.cpp qqmljsannotation_p.h
qqmljsbasicblocks.cpp qqmljsbasicblocks_p.h
qqmljscodegenerator.cpp qqmljscodegenerator_p.h
qqmljscompilepass_p.h
qqmljscompiler.cpp qqmljscompiler_p.h
+ qqmljscompilerstats.cpp qqmljscompilerstats_p.h
+ qqmljscompilerstatsreporter.cpp qqmljscompilerstatsreporter_p.h
+ qqmljscontextualtypes_p.h
qqmljsfunctioninitializer.cpp qqmljsfunctioninitializer_p.h
qqmljsimporter.cpp qqmljsimporter_p.h
qqmljsimportvisitor.cpp qqmljsimportvisitor_p.h
+ qqmljslinter.cpp qqmljslinter_p.h
+ qqmljslintercodegen.cpp qqmljslintercodegen_p.h
qqmljsliteralbindingcheck.cpp qqmljsliteralbindingcheck_p.h
- qqmljsvaluetypefromstringcheck.cpp qqmljsvaluetypefromstringcheck_p.h
qqmljsloadergenerator.cpp qqmljsloadergenerator_p.h
- qqmljslogger_p.h qqmljslogger.cpp
- qqmljsloggingutils.h qqmljsloggingutils.cpp qqmljsloggingutils_p.h
- qqmljsmetatypes_p.h qqmljsmetatypes.cpp
- qqmljsoptimizations_p.h qqmljsoptimizations.cpp
+ qqmljslogger.cpp qqmljslogger_p.h
+ qqmljsloggingutils.cpp qqmljsloggingutils.h qqmljsloggingutils_p.h
+ qqmljsmetatypes.cpp qqmljsmetatypes_p.h
+ qqmljsoptimizations.cpp qqmljsoptimizations_p.h
qqmljsregistercontent.cpp qqmljsregistercontent_p.h
qqmljsresourcefilemapper.cpp qqmljsresourcefilemapper_p.h
qqmljsscope.cpp qqmljsscope_p.h
qqmljsscopesbyid_p.h
- qqmljscontextualtypes_p.h
qqmljsshadowcheck.cpp qqmljsshadowcheck_p.h
qqmljsstoragegeneralizer.cpp qqmljsstoragegeneralizer_p.h
+ qqmljsstorageinitializer.cpp qqmljsstorageinitializer_p.h
qqmljstypedescriptionreader.cpp qqmljstypedescriptionreader_p.h
qqmljstypepropagator.cpp qqmljstypepropagator_p.h
qqmljstypereader.cpp qqmljstypereader_p.h
qqmljstyperesolver.cpp qqmljstyperesolver_p.h
- qresourcerelocater.cpp qresourcerelocater_p.h
- qqmljsutils_p.h qqmljsutils.cpp
- qqmljslinter_p.h qqmljslinter.cpp
- qqmljslintercodegen_p.h qqmljslintercodegen.cpp
- qqmlsa_p.h qqmlsa.h qqmlsa.cpp
+ qqmljsutils.cpp qqmljsutils_p.h
+ qqmljsvaluetypefromstringcheck.cpp qqmljsvaluetypefromstringcheck_p.h
+ qqmlsa.cpp qqmlsa.h qqmlsa_p.h
qqmlsaconstants.h
- qqmlsasourcelocation.h qqmlsasourcelocation.cpp qqmlsasourcelocation_p.h
+ qqmlsasourcelocation.cpp qqmlsasourcelocation.h qqmlsasourcelocation_p.h
+ qresourcerelocater.cpp qresourcerelocater_p.h
NO_UNITY_BUILD_SOURCES
qqmljsoptimizations.cpp
PUBLIC_LIBRARIES
diff --git a/src/qmlcompiler/qdeferredpointer_p.h b/src/qmlcompiler/qdeferredpointer_p.h
index e4d5eb6df3..4bd3b18326 100644
--- a/src/qmlcompiler/qdeferredpointer_p.h
+++ b/src/qmlcompiler/qdeferredpointer_p.h
@@ -155,6 +155,14 @@ public:
return (m_factory && m_factory->isValid()) ? m_factory.data() : nullptr;
}
+ void resetFactory(const Factory& newFactory) const
+ {
+ const bool wasAlreadyLoaded = !factory();
+ *m_factory = newFactory;
+ if (wasAlreadyLoaded)
+ lazyLoad();
+ }
+
private:
friend class QDeferredWeakPointer<T>;
diff --git a/src/qmlcompiler/qqmljsbasicblocks.cpp b/src/qmlcompiler/qqmljsbasicblocks.cpp
index 392a8b9ba7..1696016f79 100644
--- a/src/qmlcompiler/qqmljsbasicblocks.cpp
+++ b/src/qmlcompiler/qqmljsbasicblocks.cpp
@@ -28,10 +28,6 @@ void QQmlJSBasicBlocks::dumpBasicBlocks()
for (auto reg : block.readRegisters) {
debug << reg << ", ";
}
- debug << "\n readTypes[" << block.readTypes.size() << "]: ";
- for (const auto &type : block.readTypes) {
- debug << type->augmentedInternalName() << ", ";
- }
debug << "\n jumpTarget: " << block.jumpTarget;
debug << "\n jumpIsUnConditional: " << block.jumpIsUnconditional;
debug << "\n isReturnBlock: " << block.isReturnBlock;
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index 9f609f39fb..5c98d7b2be 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -150,7 +150,7 @@ QQmlJSAotFunction QQmlJSCodeGenerator::run(const Function *function,
e.variableName = u"r%1_%2"_s
.arg(registerIndex)
.arg(numRegisterVariablesPerIndex[registerIndex]++);
- e.storedType = m_typeResolver->comparableType(seenType);
+ e.storedType = seenType;
}
++e.numTracked;
};
@@ -213,20 +213,19 @@ QT_WARNING_POP
if (!registerIsArgument
&& registerIndex != Accumulator
&& registerIndex != This
- && !m_typeResolver->registerIsStoredIn(
+ && !m_typeResolver->registerContains(
function->registerTypes[registerIndex - firstRegisterIndex()],
m_typeResolver->voidType())) {
result.code += registerIt->variableName + u" = "_s;
result.code += convertStored(m_typeResolver->voidType(), storedType, QString());
- } else if (registerIsArgument && m_typeResolver->registerIsStoredIn(
+ } else if (registerIsArgument && registerIsStoredIn(
argumentType(registerIndex), storedType)) {
const int argumentIndex = registerIndex - FirstArgument;
const QQmlJSRegisterContent argument
= m_function->argumentTypes[argumentIndex];
- const QQmlJSRegisterContent original
- = m_typeResolver->original(argument);
+ const QQmlJSRegisterContent originalArgument = original(argument);
- const bool needsConversion = argument != original;
+ const bool needsConversion = argument != originalArgument;
if (!isPointer && registerIt->numTracked == 1 && !needsConversion) {
// Not a pointer, never written to, and doesn't need any initial conversion.
// This is a readonly argument.
@@ -240,11 +239,11 @@ QT_WARNING_POP
result.code += registerIt->variableName + u" = "_s;
const QString originalValue
- = u"(*static_cast<"_s + castTargetName(original.storedType())
+ = u"(*static_cast<"_s + castTargetName(originalArgument.storedType())
+ u"*>(argv["_s + QString::number(argumentIndex + 1) + u"]))"_s;
if (needsConversion)
- result.code += conversion(original, argument, originalValue);
+ result.code += conversion(originalArgument, argument, originalValue);
else
result.code += originalValue;
} else {
@@ -263,7 +262,7 @@ QT_WARNING_POP
if (function->returnType.isValid()) {
signature += u" argTypes[0] = %1;\n"_s.arg(
- metaType(m_typeResolver->containedType(function->returnType)));
+ metaType(function->returnType.containedType()));
} else {
signature += u" argTypes[0] = QMetaType();\n"_s;
}
@@ -289,7 +288,7 @@ void QQmlJSCodeGenerator::generateReturnError()
m_body += u"if (argv[0]) {\n"_s;
- const auto contained = m_typeResolver->containedType(ret);
+ const auto contained = ret.containedType();
const auto stored = ret.storedType();
if (contained->isReferenceType() && stored->isReferenceType()) {
m_body += u" *static_cast<"_s
@@ -300,7 +299,7 @@ void QQmlJSCodeGenerator::generateReturnError()
+ stored->internalName() + u"();\n"_s;
} else {
m_body += u" const QMetaType returnType = "_s
- + metaType(m_typeResolver->containedType(ret)) + u";\n"_s;
+ + metaType(ret.containedType()) + u";\n"_s;
m_body += u" returnType.destruct(argv[0]);\n"_s;
m_body += u" returnType.construct(argv[0]);\n "_s;
}
@@ -332,15 +331,15 @@ void QQmlJSCodeGenerator::generate_Ret()
m_body += signalUndefined;
}
- } else if (m_typeResolver->registerIsStoredIn(
+ } else if (registerIsStoredIn(
m_state.accumulatorIn(), m_typeResolver->varType())) {
m_body += u" if (!"_s + in + u".isValid())\n"_s;
m_body += u" "_s + signalUndefined;
- } else if (m_typeResolver->registerIsStoredIn(
+ } else if (registerIsStoredIn(
m_state.accumulatorIn(), m_typeResolver->jsPrimitiveType())) {
m_body += u" if ("_s + in + u".type() == QJSPrimitiveValue::Undefined)\n"_s;
m_body += u" "_s + signalUndefined;
- } else if (m_typeResolver->registerIsStoredIn(
+ } else if (registerIsStoredIn(
m_state.accumulatorIn(), m_typeResolver->jsValueType())) {
m_body += u" if ("_s + in + u".isUndefined())\n"_s;
m_body += u" "_s + signalUndefined;
@@ -352,15 +351,20 @@ void QQmlJSCodeGenerator::generate_Ret()
return;
}
- const auto contained = m_typeResolver->containedType(m_function->returnType);
+ const auto contained = m_function->returnType.containedType();
const auto stored = m_function->returnType.storedType();
if (m_typeResolver->equals(contained, stored)
|| (contained->isReferenceType() && stored->isReferenceType())) {
+ // We can always std::move here, no matter what the optimization pass has detected. The
+ // function returns and nothing can access the accumulator register anymore afterwards.
m_body += u" *static_cast<"_s
+ stored->augmentedInternalName()
+ u" *>(argv[0]) = "_s
- + conversion(m_state.accumulatorIn(), m_function->returnType,
- consumedAccumulatorVariableIn())
+ + conversion(
+ m_state.accumulatorIn(), m_function->returnType,
+ m_typeResolver->isTriviallyCopyable(m_state.accumulatorIn().storedType())
+ ? in
+ : u"std::move("_s + in + u')')
+ u";\n"_s;
} else if (m_typeResolver->registerContains(m_state.accumulatorIn(), contained)) {
m_body += u" const QMetaType returnType = "_s + contentType(m_state.accumulatorIn(), in)
@@ -678,9 +682,11 @@ void QQmlJSCodeGenerator::generate_LoadQmlContextPropertyLookup(int index)
const int nameIndex = m_jsUnitGenerator->lookupNameIndex(index);
const QString name = m_jsUnitGenerator->stringForIndex(nameIndex);
if (m_state.accumulatorOut().variant() == QQmlJSRegisterContent::JavaScriptGlobal) {
+ // This produces a QJSValue. The QQmlJSMetaProperty used to analyze it may have more details
+ // but the QQmlJSAotContext API does not reflect them.
m_body += m_state.accumulatorVariableOut + u" = "_s
+ conversion(
- m_typeResolver->original(m_state.accumulatorOut()), m_state.accumulatorOut(),
+ m_typeResolver->jsValueType(), m_state.accumulatorOut(),
u"aotContext->javaScriptGlobalProperty("_s + QString::number(nameIndex) + u")")
+ u";\n"_s;
return;
@@ -764,19 +770,19 @@ void QQmlJSCodeGenerator::generate_LoadElement(int base)
const QQmlJSRegisterContent baseType = registerType(base);
if (!baseType.isList()
- && !m_typeResolver->registerIsStoredIn(baseType, m_typeResolver->stringType())) {
+ && !registerIsStoredIn(baseType, m_typeResolver->stringType())) {
reject(u"LoadElement with non-list base type "_s + baseType.descriptiveName());
return;
}
const QString voidAssignment = u" "_s + m_state.accumulatorVariableOut + u" = "_s +
- conversion(m_typeResolver->globalType(m_typeResolver->voidType()),
+ conversion(global(m_typeResolver->voidType()),
m_state.accumulatorOut(), QString()) + u";\n"_s;
QString indexName = m_state.accumulatorVariableIn;
QQmlJSScope::ConstPtr indexType;
if (m_typeResolver->isNumeric(m_state.accumulatorIn())) {
- indexType = m_typeResolver->containedType(m_state.accumulatorIn());
+ indexType = m_state.accumulatorIn().containedType();
} else if (m_state.accumulatorIn().isConversion()) {
const auto target = m_typeResolver->extractNonVoidFromOptionalType(m_state.accumulatorIn());
if (m_typeResolver->isNumeric(target)) {
@@ -805,9 +811,9 @@ void QQmlJSCodeGenerator::generate_LoadElement(int base)
+ u"else "_s;
}
- if (m_typeResolver->registerIsStoredIn(baseType, m_typeResolver->listPropertyType())) {
+ if (registerIsStoredIn(baseType, m_typeResolver->listPropertyType())) {
// Our QQmlListProperty only keeps plain QObject*.
- const auto elementType = m_typeResolver->globalType(m_typeResolver->qObjectType());
+ const auto elementType = global(m_typeResolver->qObjectType());
m_body += u"if ("_s + indexName + u" < "_s + baseName
+ u".count(&"_s + baseName + u"))\n"_s;
@@ -820,12 +826,14 @@ void QQmlJSCodeGenerator::generate_LoadElement(int base)
return;
}
- const auto elementType = m_typeResolver->valueType(baseType);
+ // Since we can do .at() below, we know that we can natively store the element type.
+ QQmlJSRegisterContent elementType = m_typeResolver->valueType(baseType);
+ elementType = elementType.storedIn(m_typeResolver->storedType(elementType.containedType()));
QString access = baseName + u".at("_s + indexName + u')';
// TODO: Once we get a char type in QML, use it here.
- if (m_typeResolver->registerIsStoredIn(baseType, m_typeResolver->stringType()))
+ if (registerIsStoredIn(baseType, m_typeResolver->stringType()))
access = u"QString("_s + access + u")"_s;
else if (m_state.isRegisterAffectedBySideEffects(base))
reject(u"LoadElement on a sequence potentially affected by side effects"_s);
@@ -844,7 +852,7 @@ void QQmlJSCodeGenerator::generate_StoreElement(int base, int index)
INJECT_TRACE_INFO(generate_StoreElement);
const QQmlJSRegisterContent baseType = registerType(base);
- const QQmlJSScope::ConstPtr indexType = m_typeResolver->containedType(registerType(index));
+ const QQmlJSScope::ConstPtr indexType = registerType(index).containedType();
if (!m_typeResolver->isNumeric(indexType) || !baseType.isList()) {
reject(u"StoreElement with non-list base type or non-numeric arguments"_s);
@@ -860,8 +868,8 @@ void QQmlJSCodeGenerator::generate_StoreElement(int base, int index)
const QString indexName = registerVariable(index);
const auto valueType = m_typeResolver->valueType(baseType);
- const auto elementType = m_typeResolver->globalType(m_typeResolver->genericType(
- m_typeResolver->containedType(valueType)));
+ const auto elementType = global(m_typeResolver->genericType(
+ valueType.containedType()));
addInclude(u"QtQml/qjslist.h"_s);
if (!m_typeResolver->isNativeArrayIndex(indexType))
@@ -871,7 +879,7 @@ void QQmlJSCodeGenerator::generate_StoreElement(int base, int index)
else
m_body += u"{\n"_s;
- if (m_typeResolver->registerIsStoredIn(baseType, m_typeResolver->listPropertyType())) {
+ if (registerIsStoredIn(baseType, m_typeResolver->listPropertyType())) {
m_body += u" if ("_s + indexName + u" < "_s + baseName + u".count(&"_s + baseName
+ u"))\n"_s;
m_body += u" "_s + baseName + u".replace(&"_s + baseName
@@ -987,7 +995,7 @@ void QQmlJSCodeGenerator::generateTypeLookup(int index)
reject(u"script lookup"_s);
break;
case QQmlJSRegisterContent::MetaType: {
- if (!m_typeResolver->registerIsStoredIn(
+ if (!registerIsStoredIn(
m_state.accumulatorOut(), m_typeResolver->metaObjectType())) {
// TODO: Can we trigger this somehow?
// It might be impossible, but we better be safe here.
@@ -1008,7 +1016,7 @@ void QQmlJSCodeGenerator::generateTypeLookup(int index)
void QQmlJSCodeGenerator::generateVariantEqualityComparison(
const QQmlJSRegisterContent &nonStorableContent, const QString &registerName, bool invert)
{
- const auto nonStorableType = m_typeResolver->containedType(nonStorableContent);
+ const auto nonStorableType = nonStorableContent.containedType();
QQmlJSScope::ConstPtr comparedType =
m_typeResolver->equals(nonStorableType, m_typeResolver->nullType())
? m_typeResolver->nullType()
@@ -1070,11 +1078,10 @@ void QQmlJSCodeGenerator::generateVariantEqualityComparison(
// Therefore, use the underlying type right away.
const auto contained = storableContent.isEnumeration()
? storableContent.storedType()
- : m_typeResolver->containedType(storableContent);
+ : storableContent.containedType();
if (contained->isReferenceType()) {
- const QQmlJSRegisterContent comparable
- = m_typeResolver->builtinType(m_typeResolver->qObjectType());
+ const QQmlJSRegisterContent comparable = builtin(m_typeResolver->qObjectType());
m_body += m_state.accumulatorVariableOut + u" = "_s + (invert ? u"!"_s : QString()) + u"(("
+ varRegisterName + u".metaType().flags() & QMetaType::PointerToQObject) "_s
+ u" && "_s + conversion(storableContent, comparable, typedRegisterName) + u" == "_s
@@ -1083,8 +1090,7 @@ void QQmlJSCodeGenerator::generateVariantEqualityComparison(
}
if (m_typeResolver->isPrimitive(contained)) {
- const QQmlJSRegisterContent comparable
- = m_typeResolver->builtinType(m_typeResolver->jsPrimitiveType());
+ const QQmlJSRegisterContent comparable = builtin(m_typeResolver->jsPrimitiveType());
m_body += m_state.accumulatorVariableOut + u" = "_s + (invert ? u"!"_s : QString())
+ conversion(storableContent, comparable, typedRegisterName)
+ u".strictlyEquals("_s
@@ -1260,7 +1266,7 @@ bool QQmlJSCodeGenerator::generateContentPointerCheck(
const QString &variable, const QString &errorMessage)
{
const QQmlJSScope::ConstPtr scope = required;
- const QQmlJSScope::ConstPtr input = m_typeResolver->containedType(actual);
+ const QQmlJSScope::ConstPtr input = actual.containedType();
if (QQmlJSUtils::searchBaseAndExtensionTypes(input,
[&](const QQmlJSScope::ConstPtr &base) {
return m_typeResolver->equals(base, scope);
@@ -1428,7 +1434,7 @@ void QQmlJSCodeGenerator::generate_GetLookupHelper(int index)
Q_ASSERT(m_state.accumulatorOut().isProperty());
- if (m_typeResolver->registerIsStoredIn(accumulatorIn, m_typeResolver->jsValueType())) {
+ if (registerIsStoredIn(accumulatorIn, m_typeResolver->jsValueType())) {
reject(u"lookup in QJSValue"_s);
} else if (isReferenceType) {
const QString inputPointer = resolveQObjectPointer(
@@ -1452,7 +1458,7 @@ void QQmlJSCodeGenerator::generate_GetLookupHelper(int index)
if (stored->isListProperty()) {
m_body += m_state.accumulatorVariableOut + u" = "_s;
m_body += conversion(
- m_typeResolver->globalType(m_typeResolver->sizeType()),
+ global(m_typeResolver->sizeType()),
m_state.accumulatorOut(),
m_state.accumulatorVariableIn + u".count("_s + u'&'
+ m_state.accumulatorVariableIn + u')');
@@ -1460,19 +1466,18 @@ void QQmlJSCodeGenerator::generate_GetLookupHelper(int index)
} else if (stored->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence
|| m_typeResolver->equals(stored, m_typeResolver->stringType())) {
m_body += m_state.accumulatorVariableOut + u" = "_s
- + conversion(m_typeResolver->globalType(m_typeResolver->sizeType()),
+ + conversion(global(m_typeResolver->sizeType()),
m_state.accumulatorOut(),
m_state.accumulatorVariableIn + u".length()"_s)
+ u";\n"_s;
} else {
reject(u"access to 'length' property of sequence wrapped in non-sequence"_s);
}
- } else if (m_typeResolver->registerIsStoredIn(accumulatorIn,
- m_typeResolver->variantMapType())) {
+ } else if (registerIsStoredIn(accumulatorIn, m_typeResolver->variantMapType())) {
QString mapLookup = m_state.accumulatorVariableIn + u"["_s
+ QQmlJSUtils::toLiteral(m_jsUnitGenerator->lookupName(index)) + u"]"_s;
m_body += m_state.accumulatorVariableOut + u" = "_s;
- m_body += conversion(m_typeResolver->globalType(m_typeResolver->varType()),
+ m_body += conversion(global(m_typeResolver->varType()),
m_state.accumulatorOut(), mapLookup);
m_body += u";\n"_s;
} else {
@@ -1543,7 +1548,7 @@ QString QQmlJSCodeGenerator::setLookupPreparation(
if (m_typeResolver->registerContains(content, content.storedType()))
return QString();
- if (m_typeResolver->registerIsStoredIn(content, m_typeResolver->varType())) {
+ if (registerIsStoredIn(content, m_typeResolver->varType())) {
return u"const QMetaType argType = aotContext->lookupResultMetaType("_s
+ QString::number(lookup) + u");\n"_s
+ u"if (argType.isValid())\n "_s + arg + u".convert(argType)";
@@ -1594,7 +1599,7 @@ void QQmlJSCodeGenerator::generate_SetLookup(int index, int baseReg)
QString preparation;
QString argType;
if (!m_typeResolver->registerContains(
- m_state.accumulatorIn(), m_typeResolver->containedType(property))) {
+ m_state.accumulatorIn(), property.containedType())) {
m_body += u"auto converted = "_s
+ conversion(m_state.accumulatorIn(), property, consumedAccumulatorVariableIn())
+ u";\n"_s;
@@ -1718,9 +1723,7 @@ QString QQmlJSCodeGenerator::argumentsList(int argc, int argv, QString *outVar)
if (!m_typeResolver->registerContains(m_state.accumulatorOut(), outType)) {
if (m_typeResolver->equals(outType, m_typeResolver->varType())
|| m_typeResolver->equals(outType, m_typeResolver->jsPrimitiveType())) {
- m_body += u'('
- + metaType(m_typeResolver->containedType(m_state.accumulatorOut()))
- + u')';
+ m_body += u'(' + metaType(m_state.accumulatorOut().containedType()) + u')';
}
}
m_body += u";\n";
@@ -1796,7 +1799,7 @@ bool QQmlJSCodeGenerator::inlineStringMethod(const QString &name, int base, int
m_body += m_state.accumulatorVariableOut + u" = "_s;
if (m_typeResolver->isNumeric(input))
- m_body += ret(arg(m_typeResolver->containedType(input)));
+ m_body += ret(arg(input.containedType()));
else if (m_typeResolver->registerContains(input, m_typeResolver->boolType()))
m_body += ret(arg(m_typeResolver->boolType()));
else
@@ -2062,13 +2065,11 @@ bool QQmlJSCodeGenerator::inlineConsoleMethod(const QString &name, int argc, int
m_body += u" bool firstArgIsCategory = false;\n";
const QQmlJSRegisterContent firstArg = argc > 0 ? registerType(argv) : QQmlJSRegisterContent();
- // We could check for internalName == "QQmlLoggingCategory" here, but we don't want to
- // because QQmlLoggingCategory is not a builtin. Tying the specific internal name and
- // intheritance hierarchy in here would be fragile.
- // TODO: We could drop the check for firstArg in some cases if we made some base class
- // of QQmlLoggingCategory a builtin.
+ // We could check whether the first argument is a QQmlLoggingCategoryBase here, and we should
+ // because QQmlLoggingCategoryBase is now a builtin.
+ // TODO: The run time check for firstArg is obsolete.
const bool firstArgIsReference = argc > 0
- && m_typeResolver->containedType(firstArg)->isReferenceType();
+ && firstArg.containedType()->isReferenceType();
if (firstArgIsReference) {
m_body += u" QObject *firstArg = ";
@@ -2187,7 +2188,7 @@ bool QQmlJSCodeGenerator::inlineArrayMethod(const QString &name, int base, int a
call += u")";
const auto outType = baseType.storedType()->isListProperty()
- ? m_typeResolver->globalType(m_typeResolver->qObjectListType())
+ ? global(m_typeResolver->qObjectListType())
: baseType;
m_body += m_state.accumulatorVariableOut + u" = "_s
@@ -2345,9 +2346,9 @@ void QQmlJSCodeGenerator::generate_Construct(int func, int argc, int argv)
INJECT_TRACE_INFO(generate_Construct);
Q_UNUSED(func);
- const auto original = m_typeResolver->original(m_state.accumulatorOut());
+ const auto originalResult = original(m_state.accumulatorOut());
- if (m_typeResolver->registerContains(original, m_typeResolver->dateTimeType())) {
+ if (m_typeResolver->registerContains(originalResult, m_typeResolver->dateTimeType())) {
m_body += m_state.accumulatorVariableOut + u" = ";
if (argc == 0) {
m_body += conversion(
@@ -2380,7 +2381,7 @@ void QQmlJSCodeGenerator::generate_Construct(int func, int argc, int argv)
return;
}
- if (m_typeResolver->registerContains(original, m_typeResolver->variantListType())) {
+ if (m_typeResolver->registerContains(originalResult, m_typeResolver->variantListType())) {
rejectIfBadArray();
if (argc == 1
@@ -2392,7 +2393,7 @@ void QQmlJSCodeGenerator::generate_Construct(int func, int argc, int argv)
+ u"QLatin1String(\"Invalid array length\"));\n"_s;
const QString indexName = registerVariable(argv);
- const auto indexType = m_typeResolver->containedType(registerType(argv));
+ const auto indexType = registerType(argv).containedType();
if (!m_typeResolver->isNativeArrayIndex(indexType)) {
m_body += u"if (!QJSNumberCoercion::isArrayIndex("_s + indexName + u")) {\n"_s
+ error;
@@ -2462,8 +2463,7 @@ void QQmlJSCodeGenerator::generate_ThrowException()
generateSetInstructionPointer();
m_body += u"aotContext->engine->throwError("_s
- + conversion(m_state.accumulatorIn(), m_typeResolver->globalType(
- m_typeResolver->jsValueType()),
+ + conversion(m_state.accumulatorIn(), global(m_typeResolver->jsValueType()),
m_state.accumulatorVariableIn) + u");\n"_s;
generateReturnError();
m_skipUntilNextLabel = true;
@@ -2591,10 +2591,14 @@ void QQmlJSCodeGenerator::generate_IteratorNext(int value, int offset)
reject(u"using non-iterator as iterator"_s);
m_body += u"if (" + m_state.accumulatorVariableIn + u"->hasNext(" + qjsList + u")) {\n ";
+
+ // We know that this works because we can do ->next() below.
+ QQmlJSRegisterContent iteratorValue = m_typeResolver->valueType(iteratorContent);
+ iteratorValue = iteratorValue.storedIn(iteratorValue.containedType());
+
m_body += changedRegisterVariable() + u" = "
+ conversion(
- m_typeResolver->valueType(iteratorContent),
- m_state.changedRegister(),
+ iteratorValue, m_state.changedRegister(),
m_state.accumulatorVariableIn + u"->next(" + qjsList + u')')
+ u";\n";
m_body += u"} else {\n ";
@@ -2673,7 +2677,7 @@ void QQmlJSCodeGenerator::generate_DefineObjectLiteral(int internalClassId, int
return;
}
- const QQmlJSScope::ConstPtr contained = m_typeResolver->containedType(m_state.accumulatorOut());
+ const QQmlJSScope::ConstPtr contained = m_state.accumulatorOut().containedType();
const int classSize = m_jsUnitGenerator->jsClassSize(internalClassId);
Q_ASSERT(argc >= classSize);
@@ -2698,7 +2702,7 @@ void QQmlJSCodeGenerator::generate_DefineObjectLiteral(int internalClassId, int
m_body += u"{ "_s
+ conversion(
registerType(nameArg),
- m_typeResolver->globalType(m_typeResolver->stringType()),
+ global(m_typeResolver->stringType()),
consumedRegisterVariable(nameArg))
+ u", "_s;
@@ -2721,7 +2725,7 @@ void QQmlJSCodeGenerator::generate_DefineObjectLiteral(int internalClassId, int
if (m_typeResolver->registerContains(m_state.accumulatorOut(), stored)) {
m_body += u"()";
} else if (isVariantOrPrimitive) {
- m_body += u'(' + metaType(m_typeResolver->containedType(m_state.accumulatorOut())) + u')';
+ m_body += u'(' + metaType(m_state.accumulatorOut().containedType()) + u')';
} else {
reject(u"storing an object literal in an unsupported container %1"_s
.arg(stored->internalName()));
@@ -2889,15 +2893,13 @@ void QQmlJSCodeGenerator::generate_CheckException()
void QQmlJSCodeGenerator::generate_CmpEqNull()
{
INJECT_TRACE_INFO(generate_CmpEqNull);
- generateEqualityOperation(
- m_typeResolver->globalType(m_typeResolver->nullType()), QString(), u"equals"_s, false);
+ generateEqualityOperation(global(m_typeResolver->nullType()), QString(), u"equals"_s, false);
}
void QQmlJSCodeGenerator::generate_CmpNeNull()
{
INJECT_TRACE_INFO(generate_CmlNeNull);
- generateEqualityOperation(
- m_typeResolver->globalType(m_typeResolver->nullType()), QString(), u"equals"_s, true);
+ generateEqualityOperation(global(m_typeResolver->nullType()), QString(), u"equals"_s, true);
}
QString QQmlJSCodeGenerator::getLookupPreparation(
@@ -2906,7 +2908,7 @@ QString QQmlJSCodeGenerator::getLookupPreparation(
if (m_typeResolver->registerContains(content, content.storedType()))
return QString();
- if (m_typeResolver->registerIsStoredIn(content, m_typeResolver->varType())) {
+ if (registerIsStoredIn(content, m_typeResolver->varType())) {
return var + u" = QVariant(aotContext->lookupResultMetaType("_s
+ QString::number(lookup) + u"))"_s;
}
@@ -2920,8 +2922,8 @@ QString QQmlJSCodeGenerator::contentPointer(const QQmlJSRegisterContent &content
if (m_typeResolver->registerContains(content, stored))
return u'&' + var;
- if (m_typeResolver->registerIsStoredIn(content, m_typeResolver->varType())
- || m_typeResolver->registerIsStoredIn(content, m_typeResolver->jsPrimitiveType())) {
+ if (registerIsStoredIn(content, m_typeResolver->varType())
+ || registerIsStoredIn(content, m_typeResolver->jsPrimitiveType())) {
return var + u".data()"_s;
}
@@ -2929,11 +2931,11 @@ QString QQmlJSCodeGenerator::contentPointer(const QQmlJSRegisterContent &content
return u'&' + var;
if (m_typeResolver->isNumeric(content.storedType())
- && m_typeResolver->containedType(content)->scopeType() == QQmlSA::ScopeType::EnumScope) {
+ && content.containedType()->scopeType() == QQmlSA::ScopeType::EnumScope) {
return u'&' + var;
}
- if (stored->isListProperty() && m_typeResolver->containedType(content)->isListProperty())
+ if (stored->isListProperty() && content.containedType()->isListProperty())
return u'&' + var;
reject(u"content pointer of unsupported wrapper type "_s + content.descriptiveName());
@@ -2943,12 +2945,12 @@ QString QQmlJSCodeGenerator::contentPointer(const QQmlJSRegisterContent &content
QString QQmlJSCodeGenerator::contentType(const QQmlJSRegisterContent &content, const QString &var)
{
const QQmlJSScope::ConstPtr stored = content.storedType();
- const QQmlJSScope::ConstPtr contained = m_typeResolver->containedType(content);
+ const QQmlJSScope::ConstPtr contained = content.containedType();
if (m_typeResolver->equals(contained, stored))
return metaTypeFromType(stored);
if (m_typeResolver->equals(stored, m_typeResolver->varType())
- || m_typeResolver->registerIsStoredIn(content, m_typeResolver->jsPrimitiveType())) {
+ || registerIsStoredIn(content, m_typeResolver->jsPrimitiveType())) {
return var + u".metaType()"_s; // We expect the container to be initialized
}
@@ -2971,8 +2973,7 @@ void QQmlJSCodeGenerator::generate_CmpEqInt(int lhsConst)
INJECT_TRACE_INFO(generate_CmpEqInt);
generateEqualityOperation(
- m_typeResolver->globalType(m_typeResolver->int32Type()), QString::number(lhsConst),
- u"equals"_s, false);
+ global(m_typeResolver->int32Type()), QString::number(lhsConst), u"equals"_s, false);
}
void QQmlJSCodeGenerator::generate_CmpNeInt(int lhsConst)
@@ -2980,8 +2981,7 @@ void QQmlJSCodeGenerator::generate_CmpNeInt(int lhsConst)
INJECT_TRACE_INFO(generate_CmpNeInt);
generateEqualityOperation(
- m_typeResolver->globalType(m_typeResolver->int32Type()), QString::number(lhsConst),
- u"equals"_s, true);
+ global(m_typeResolver->int32Type()), QString::number(lhsConst), u"equals"_s, true);
}
void QQmlJSCodeGenerator::generate_CmpEq(int lhs)
@@ -3054,9 +3054,9 @@ void QQmlJSCodeGenerator::generate_As(int lhs)
// If the original output is a conversion, we're supposed to check for the contained
// type and if it doesn't match, set the result to null or undefined.
- const QQmlJSRegisterContent originalContent = m_typeResolver->original(outputContent);
- const QQmlJSScope::ConstPtr target = originalContent.storedType()->isReferenceType()
- ? m_typeResolver->containedType(originalContent)
+ const QQmlJSRegisterContent originalContent = original(outputContent);
+ const QQmlJSScope::ConstPtr target = originalContent.containedType()->isReferenceType()
+ ? originalContent.containedType()
: m_typeResolver->extractNonVoidFromOptionalType(originalContent);
if (!target) {
@@ -3089,18 +3089,17 @@ void QQmlJSCodeGenerator::generate_As(int lhs)
return;
}
- if (m_typeResolver->registerIsStoredIn(inputContent, m_typeResolver->varType())
- || m_typeResolver->registerIsStoredIn(inputContent, m_typeResolver->jsPrimitiveType())) {
+ if (registerIsStoredIn(inputContent, m_typeResolver->varType())
+ || registerIsStoredIn(inputContent, m_typeResolver->jsPrimitiveType())) {
const auto source = m_typeResolver->extractNonVoidFromOptionalType(
- m_typeResolver->original(inputContent));
+ original(inputContent));
if (source && m_typeResolver->equals(source, target)) {
m_body += input + u".metaType() == "_s + metaType(target)
+ u" ? " + conversion(inputContent, outputContent, input)
+ u" : " + conversion(
- m_typeResolver->globalType(m_typeResolver->voidType()),
- outputContent, QString());
+ global(m_typeResolver->voidType()), outputContent, QString());
m_body += u";\n"_s;
return;
}
@@ -3242,7 +3241,7 @@ void QQmlJSCodeGenerator::generate_Exp(int lhs)
Q_ASSERT(m_error->isValid() || !lhsString.isEmpty());
Q_ASSERT(m_error->isValid() || !rhsString.isEmpty());
- const QQmlJSRegisterContent originalOut = m_typeResolver->original(m_state.accumulatorOut());
+ const QQmlJSRegisterContent originalOut = original(m_state.accumulatorOut());
m_body += m_state.accumulatorVariableOut + u" = "_s;
m_body += conversion(
originalOut, m_state.accumulatorOut(),
@@ -3383,11 +3382,11 @@ void QQmlJSCodeGenerator::generateEqualityOperation(
const auto rhsContained = rhsIsOptional
? m_typeResolver->extractNonVoidFromOptionalType(rhsContent)
- : m_typeResolver->containedType(rhsContent);
+ : rhsContent.containedType();
const auto lhsContained = lhsIsOptional
? m_typeResolver->extractNonVoidFromOptionalType(lhsContent)
- : m_typeResolver->containedType(lhsContent);
+ : lhsContent.containedType();
const bool isStrict = function == "strictlyEquals"_L1;
const bool strictlyComparableWithVar
@@ -3409,21 +3408,21 @@ void QQmlJSCodeGenerator::generateEqualityOperation(
};
const auto retrieveOriginal = [this](const QQmlJSRegisterContent &content) {
- const auto contained = m_typeResolver->containedType(content);
- const auto original = m_typeResolver->original(content);
- const auto containedOriginal = m_typeResolver->containedType(original);
+ const auto contained = content.containedType();
+ const auto originalContent = original(content);
+ const auto containedOriginal = originalContent.containedType();
if (m_typeResolver->equals(
- m_typeResolver->genericType(containedOriginal), original.storedType())) {
+ m_typeResolver->genericType(containedOriginal), originalContent.storedType())) {
// The original type doesn't need any wrapping.
- return original;
+ return originalContent;
} else if (m_typeResolver->equals(contained, containedOriginal)) {
- if (original.isConversion()) {
+ if (originalContent.isConversion()) {
// The original conversion origins are more accurate
- return original.storedIn(content.storedType());
+ return originalContent.storedIn(content.storedType());
}
} else if (m_typeResolver->canHold(contained, containedOriginal)) {
- return original.storedIn(content.storedType());
+ return originalContent.storedIn(content.storedType());
}
return content;
@@ -3597,7 +3596,7 @@ void QQmlJSCodeGenerator::generateCompareOperation(int lhs, const QString &cppOp
const auto lhsType = registerType(lhs);
const QQmlJSScope::ConstPtr compareType =
m_typeResolver->isNumeric(lhsType) && m_typeResolver->isNumeric(m_state.accumulatorIn())
- ? m_typeResolver->merge(lhsType, m_state.accumulatorIn()).storedType()
+ ? m_typeResolver->merge(lhsType.storedType(), m_state.accumulatorIn().storedType())
: m_typeResolver->jsPrimitiveType();
m_body += conversion(
@@ -3636,12 +3635,16 @@ void QQmlJSCodeGenerator::generateArithmeticOperation(
Q_ASSERT(m_error->isValid() || !lhs.isEmpty());
Q_ASSERT(m_error->isValid() || !rhs.isEmpty());
- const QQmlJSRegisterContent originalOut = m_typeResolver->original(m_state.accumulatorOut());
+ const QQmlJSRegisterContent originalOut = original(m_state.accumulatorOut());
m_body += m_state.accumulatorVariableOut;
m_body += u" = "_s;
+ const QString explicitCast
+ = m_typeResolver->equals(originalOut.storedType(), m_typeResolver->stringType())
+ ? originalOut.storedType()->internalName()
+ : QString();
m_body += conversion(
originalOut, m_state.accumulatorOut(),
- u'(' + lhs + u' ' + cppOperator + u' ' + rhs + u')');
+ explicitCast + u'(' + lhs + u' ' + cppOperator + u' ' + rhs + u')');
m_body += u";\n"_s;
}
@@ -3650,7 +3653,7 @@ void QQmlJSCodeGenerator::generateArithmeticConstOperation(int rhsConst, const Q
generateArithmeticOperation(
conversion(m_state.accumulatorIn(), m_state.readAccumulator(),
consumedAccumulatorVariableIn()),
- conversion(m_typeResolver->globalType(m_typeResolver->int32Type()),
+ conversion(global(m_typeResolver->int32Type()),
m_state.readAccumulator(), QString::number(rhsConst)),
cppOperator);
}
@@ -3658,7 +3661,7 @@ void QQmlJSCodeGenerator::generateArithmeticConstOperation(int rhsConst, const Q
void QQmlJSCodeGenerator::generateUnaryOperation(const QString &cppOperator)
{
const auto var = conversion(m_state.accumulatorIn(),
- m_typeResolver->original(m_state.readAccumulator()),
+ original(m_state.readAccumulator()),
consumedAccumulatorVariableIn());
if (var == m_state.accumulatorVariableOut) {
@@ -3666,8 +3669,8 @@ void QQmlJSCodeGenerator::generateUnaryOperation(const QString &cppOperator)
return;
}
- const auto original = m_typeResolver->original(m_state.accumulatorOut());
- if (m_state.accumulatorOut() == original) {
+ const auto originalResult = original(m_state.accumulatorOut());
+ if (m_state.accumulatorOut() == originalResult) {
m_body += m_state.accumulatorVariableOut + u" = "_s + var + u";\n"_s;
m_body += m_state.accumulatorVariableOut + u" = "_s
+ cppOperator + m_state.accumulatorVariableOut + u";\n"_s;
@@ -3675,7 +3678,7 @@ void QQmlJSCodeGenerator::generateUnaryOperation(const QString &cppOperator)
}
m_body += m_state.accumulatorVariableOut + u" = "_s + conversion(
- original, m_state.accumulatorOut(), cppOperator + var) + u";\n"_s;
+ originalResult, m_state.accumulatorOut(), cppOperator + var) + u";\n"_s;
}
void QQmlJSCodeGenerator::generateInPlaceOperation(const QString &cppOperator)
@@ -3693,8 +3696,8 @@ void QQmlJSCodeGenerator::generateInPlaceOperation(const QString &cppOperator)
const QString var = conversion(m_state.accumulatorIn(), m_state.readAccumulator(),
consumedAccumulatorVariableIn());
- const auto original = m_typeResolver->original(m_state.accumulatorOut());
- if (m_state.accumulatorOut() == original) {
+ const auto originalResult = original(m_state.accumulatorOut());
+ if (m_state.accumulatorOut() == originalResult) {
m_body += m_state.accumulatorVariableOut + u" = "_s + var + u";\n"_s;
m_body += cppOperator + m_state.accumulatorVariableOut + u";\n"_s;
return;
@@ -3703,7 +3706,7 @@ void QQmlJSCodeGenerator::generateInPlaceOperation(const QString &cppOperator)
m_body += u"{\n"_s;
m_body += u"auto converted = "_s + var + u";\n"_s;
m_body += m_state.accumulatorVariableOut + u" = "_s + conversion(
- original, m_state.accumulatorOut(), u'('
+ originalResult, m_state.accumulatorOut(), u'('
+ cppOperator + u"converted)"_s) + u";\n"_s;
m_body += u"}\n"_s;
}
@@ -3875,10 +3878,10 @@ bool QQmlJSCodeGenerator::shouldMoveRegister(int index) const
QString QQmlJSCodeGenerator::conversion(
const QQmlJSRegisterContent &from, const QQmlJSRegisterContent &to, const QString &variable)
{
- const QQmlJSScope::ConstPtr contained = m_typeResolver->containedType(to);
+ const QQmlJSScope::ConstPtr contained = to.containedType();
// If from is QJSPrimitiveValue and to contains a primitive we coerce using QJSPrimitiveValue
- if (m_typeResolver->registerIsStoredIn(from, m_typeResolver->jsPrimitiveType())
+ if (registerIsStoredIn(from, m_typeResolver->jsPrimitiveType())
&& m_typeResolver->isPrimitive(to)) {
QString primitive = [&]() {
@@ -3904,7 +3907,7 @@ QString QQmlJSCodeGenerator::conversion(
return convertStored(m_typeResolver->jsPrimitiveType(), to.storedType(), primitive);
}
- if (m_typeResolver->registerIsStoredIn(to, contained)
+ if (registerIsStoredIn(to, contained)
|| m_typeResolver->isNumeric(to.storedType())
|| to.storedType()->isReferenceType()
|| m_typeResolver->registerContains(from, contained)) {
@@ -4018,7 +4021,7 @@ QString QQmlJSCodeGenerator::convertStored(
return variable;
const auto isBoolOrNumber = [&](const QQmlJSScope::ConstPtr &type) {
- return m_typeResolver->isNumeric(m_typeResolver->globalType(type))
+ return m_typeResolver->isNumeric(type)
|| m_typeResolver->equals(type, m_typeResolver->boolType())
|| type->scopeType() == QQmlSA::ScopeType::EnumScope;
};
@@ -4218,17 +4221,17 @@ QString QQmlJSCodeGenerator::convertStored(
QString QQmlJSCodeGenerator::convertContained(const QQmlJSRegisterContent &from, const QQmlJSRegisterContent &to, const QString &variable)
{
- const QQmlJSScope::ConstPtr containedFrom = m_typeResolver->containedType(from);
- const QQmlJSScope::ConstPtr containedTo = m_typeResolver->containedType(to);
+ const QQmlJSScope::ConstPtr containedFrom = from.containedType();
+ const QQmlJSScope::ConstPtr containedTo = to.containedType();
// Those should be handled before, by convertStored().
Q_ASSERT(!to.storedType()->isReferenceType());
- Q_ASSERT(!m_typeResolver->registerIsStoredIn(to, containedTo));
+ Q_ASSERT(!registerIsStoredIn(to, containedTo));
Q_ASSERT(!m_typeResolver->isIntegral(from.storedType()));
Q_ASSERT(!m_typeResolver->equals(containedFrom, containedTo));
- if (!m_typeResolver->registerIsStoredIn(to, m_typeResolver->varType()) &&
- !m_typeResolver->registerIsStoredIn(to, m_typeResolver->jsPrimitiveType())) {
+ if (!registerIsStoredIn(to, m_typeResolver->varType()) &&
+ !registerIsStoredIn(to, m_typeResolver->jsPrimitiveType())) {
reject(u"internal conversion into unsupported wrapper type."_s);
return QString();
}
@@ -4253,9 +4256,7 @@ QString QQmlJSCodeGenerator::convertContained(const QQmlJSRegisterContent &from,
input = variable;
argPointer = contentPointer(from, u"arg"_s);
} else {
- const QQmlJSRegisterContent argument
- = m_typeResolver->globalType(argumentType)
- .storedIn(m_typeResolver->genericType(argumentType));
+ const QQmlJSRegisterContent argument = global(argumentType);
input = conversion(from, argument, variable);
argPointer = contentPointer(argument, u"arg"_s);
}
@@ -4268,8 +4269,8 @@ QString QQmlJSCodeGenerator::convertContained(const QQmlJSRegisterContent &from,
+ u", "_s + argPointer + u"); }()"_s;
}
- const auto originalFrom = m_typeResolver->original(from);
- const auto containedOriginalFrom = m_typeResolver->containedType(originalFrom);
+ const auto originalFrom = original(from);
+ const auto containedOriginalFrom = originalFrom.containedType();
if (!m_typeResolver->equals(containedFrom, containedOriginalFrom)
&& m_typeResolver->canHold(containedFrom, containedOriginalFrom)) {
// If from is simply a wrapping of a specific type into a more general one, we can convert
@@ -4309,12 +4310,12 @@ QQmlJSCodeGenerator::AccumulatorConverter::AccumulatorConverter(QQmlJSCodeGenera
// If the stored type differs or if we store in QVariant and the contained type differs,
// then we have to use a temporary ...
if (!resolver->equals(origStored, stored)
- || (!resolver->equals(origContained, resolver->containedType(accumulatorOut))
+ || (!resolver->equals(origContained, accumulatorOut.containedType())
&& resolver->equals(stored, resolver->varType()))) {
const bool storable = isTypeStorable(resolver, origStored);
generator->m_state.accumulatorVariableOut = storable ? u"retrieved"_s : QString();
- generator->m_state.setRegister(Accumulator, resolver->original(accumulatorOut));
+ generator->m_state.setRegister(Accumulator, generator->original(accumulatorOut));
generator->m_body += u"{\n"_s;
if (storable) {
generator->m_body += origStored->augmentedInternalName() + u' '
@@ -4322,7 +4323,7 @@ QQmlJSCodeGenerator::AccumulatorConverter::AccumulatorConverter(QQmlJSCodeGenera
}
} else if (generator->m_state.accumulatorVariableIn == generator->m_state.accumulatorVariableOut
&& generator->m_state.readsRegister(Accumulator)
- && resolver->registerIsStoredIn(
+ && generator->registerIsStoredIn(
generator->m_state.accumulatorOut(), resolver->varType())) {
// If both m_state.accumulatorIn and m_state.accumulatorOut are QVariant, we will need to
// prepare the output QVariant, and afterwards use the input variant. Therefore we need to
diff --git a/src/qmlcompiler/qqmljscodegenerator_p.h b/src/qmlcompiler/qqmljscodegenerator_p.h
index 2edccf31ae..ffa2c80975 100644
--- a/src/qmlcompiler/qqmljscodegenerator_p.h
+++ b/src/qmlcompiler/qqmljscodegenerator_p.h
@@ -217,7 +217,7 @@ protected:
const QQmlJSRegisterContent &to,
const QString &variable)
{
- const QQmlJSScope::ConstPtr contained = m_typeResolver->containedType(to);
+ const QQmlJSScope::ConstPtr contained = to.containedType();
if (m_typeResolver->equals(to.storedType(), contained)
|| m_typeResolver->isNumeric(to.storedType())
|| to.storedType()->isReferenceType()
@@ -230,7 +230,9 @@ protected:
// we can convert by stored type.
return convertStored(from, to.storedType(), variable);
} else {
- return convertContained(m_typeResolver->globalType(from), to, variable);
+ return convertContained(
+ m_typeResolver->globalType(from).storedIn(m_typeResolver->storedType(from)),
+ to, variable);
}
}
@@ -335,6 +337,28 @@ private:
const QQmlJSScope::ConstPtr &required, const QQmlJSRegisterContent &actual,
const QString &variable, const QString &errorMessage);
+ QQmlJSRegisterContent original(const QQmlJSRegisterContent &tracked)
+ {
+ const QQmlJSRegisterContent restored = m_typeResolver->original(tracked);
+ return restored.storedIn(m_typeResolver->originalType(tracked.storedType()));
+ }
+
+ QQmlJSRegisterContent global(const QQmlJSScope::ConstPtr &contained)
+ {
+ return m_typeResolver->globalType(contained).storedIn(contained);
+ }
+
+ QQmlJSRegisterContent builtin(const QQmlJSScope::ConstPtr &contained)
+ {
+ return m_typeResolver->builtinType(contained).storedIn(contained);
+ }
+
+ bool registerIsStoredIn(
+ const QQmlJSRegisterContent &reg, const QQmlJSScope::ConstPtr &type) const
+ {
+ return m_typeResolver->equals(reg.storedType(), type);
+ }
+
// map from instruction offset to sequential label number
QHash<int, QString> m_labels;
diff --git a/src/qmlcompiler/qqmljscompilepass_p.h b/src/qmlcompiler/qqmljscompilepass_p.h
index a18b906d8d..d396efa4de 100644
--- a/src/qmlcompiler/qqmljscompilepass_p.h
+++ b/src/qmlcompiler/qqmljscompilepass_p.h
@@ -59,7 +59,6 @@ public:
{
QList<int> jumpOrigins;
QList<int> readRegisters;
- QList<QQmlJSScope::ConstPtr> readTypes;
int jumpTarget = -1;
bool jumpIsUnconditional = false;
bool isReturnBlock = false;
@@ -95,7 +94,7 @@ public:
QList<QQmlJSRegisterContent> argumentTypes;
QList<QQmlJSRegisterContent> registerTypes;
QQmlJSRegisterContent returnType;
- QQmlJSScope::ConstPtr qmlScope;
+ QQmlJSRegisterContent qmlScope;
QByteArray code;
const SourceLocationTable *sourceLocations = nullptr;
bool isSignalHandler = false;
diff --git a/src/qmlcompiler/qqmljscompiler.cpp b/src/qmlcompiler/qqmljscompiler.cpp
index 8ecc69d1c9..d55140f964 100644
--- a/src/qmlcompiler/qqmljscompiler.cpp
+++ b/src/qmlcompiler/qqmljscompiler.cpp
@@ -6,6 +6,7 @@
#include <private/qqmlirbuilder_p.h>
#include <private/qqmljsbasicblocks_p.h>
#include <private/qqmljscodegenerator_p.h>
+#include <private/qqmljscompilerstats_p.h>
#include <private/qqmljsfunctioninitializer_p.h>
#include <private/qqmljsimportvisitor_p.h>
#include <private/qqmljslexer_p.h>
@@ -14,6 +15,7 @@
#include <private/qqmljsparser_p.h>
#include <private/qqmljsshadowcheck_p.h>
#include <private/qqmljsstoragegeneralizer_p.h>
+#include <private/qqmljsstorageinitializer_p.h>
#include <private/qqmljstypepropagator_p.h>
#include <QtCore/qfile.h>
@@ -679,7 +681,8 @@ std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> QQmlJSAotCompiler::co
const QString name = m_document->stringAt(irBinding.propertyNameIndex);
QQmlJSCompilePass::Function function = initializer.run(
context, name, astNode, irBinding, &error);
- const QQmlJSAotFunction aotFunction = doCompile(context, &function, &error);
+ const QQmlJSAotFunction aotFunction = doCompileAndRecordAotStats(
+ context, &function, &error, name, astNode->firstSourceLocation());
if (error.isValid()) {
// If it's a signal and the function just returns a closure, it's harmless.
@@ -703,7 +706,8 @@ std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> QQmlJSAotCompiler::co
&m_typeResolver, m_currentObject->location, m_currentScope->location);
QQmlJS::DiagnosticMessage error;
QQmlJSCompilePass::Function function = initializer.run(context, name, astNode, &error);
- const QQmlJSAotFunction aotFunction = doCompile(context, &function, &error);
+ const QQmlJSAotFunction aotFunction = doCompileAndRecordAotStats(
+ context, &function, &error, name, astNode->firstSourceLocation());
if (error.isValid())
return diagnose(error.message, QtWarningMsg, error.loc);
@@ -772,8 +776,13 @@ QQmlJSAotFunction QQmlJSAotCompiler::doCompile(
if (error->isValid())
return compileError();
+ QQmlJSStorageInitializer initializer(
+ m_unitGenerator, &m_typeResolver, m_logger, blocks, annotations);
+ passResult = initializer.run(function, error);
+
// Generalize all arguments, registers, and the return type.
- QQmlJSStorageGeneralizer generalizer(m_unitGenerator, &m_typeResolver, m_logger, blocks, annotations);
+ QQmlJSStorageGeneralizer generalizer(
+ m_unitGenerator, &m_typeResolver, m_logger, blocks, annotations);
passResult = generalizer.run(function, error);
if (error->isValid())
return compileError();
@@ -783,4 +792,27 @@ QQmlJSAotFunction QQmlJSAotCompiler::doCompile(
return error->isValid() ? compileError() : result;
}
+QQmlJSAotFunction QQmlJSAotCompiler::doCompileAndRecordAotStats(
+ const QV4::Compiler::Context *context, QQmlJSCompilePass::Function *function,
+ QQmlJS::DiagnosticMessage *error, const QString &name, QQmlJS::SourceLocation location)
+{
+ auto t1 = std::chrono::high_resolution_clock::now();
+ QQmlJSAotFunction result = doCompile(context, function, error);
+ auto t2 = std::chrono::high_resolution_clock::now();
+
+ if (QQmlJS::QQmlJSAotCompilerStats::recordAotStats()) {
+ QQmlJS::AotStatsEntry entry;
+ entry.codegenDuration = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1);
+ entry.functionName = name;
+ entry.errorMessage = error->message;
+ entry.line = location.startLine;
+ entry.column = location.startColumn;
+ entry.codegenSuccessful = !error->isValid();
+ QQmlJS::QQmlJSAotCompilerStats::addEntry(
+ function->qmlScope.containedType()->filePath(), entry);
+ }
+
+ return result;
+}
+
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljscompiler_p.h b/src/qmlcompiler/qqmljscompiler_p.h
index e358f76fef..94cf71b884 100644
--- a/src/qmlcompiler/qqmljscompiler_p.h
+++ b/src/qmlcompiler/qqmljscompiler_p.h
@@ -22,6 +22,7 @@
#include <private/qqmlirbuilder_p.h>
#include <private/qqmljscompilepass_p.h>
+#include <private/qqmljscompilerstats_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
#include <private/qqmljsimporter_p.h>
#include <private/qqmljslogger_p.h>
@@ -32,7 +33,7 @@
QT_BEGIN_NAMESPACE
-Q_QMLCOMPILER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcAotCompiler);
+QT_DECLARE_EXPORTED_QT_LOGGING_CATEGORY(lcAotCompiler, Q_QMLCOMPILER_EXPORT);
struct Q_QMLCOMPILER_EXPORT QQmlJSCompileError
{
@@ -97,9 +98,14 @@ protected:
QQmlJSLogger *m_logger = nullptr;
private:
- QQmlJSAotFunction doCompile(
- const QV4::Compiler::Context *context, QQmlJSCompilePass::Function *function,
- QQmlJS::DiagnosticMessage *error);
+ QQmlJSAotFunction doCompile(const QV4::Compiler::Context *context,
+ QQmlJSCompilePass::Function *function,
+ QQmlJS::DiagnosticMessage *error);
+ QQmlJSAotFunction doCompileAndRecordAotStats(const QV4::Compiler::Context *context,
+ QQmlJSCompilePass::Function *function,
+ QQmlJS::DiagnosticMessage *error,
+ const QString &name,
+ QQmlJS::SourceLocation location);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlJSAotCompiler::Flags);
diff --git a/src/qmlcompiler/qqmljscompilerstats.cpp b/src/qmlcompiler/qqmljscompilerstats.cpp
new file mode 100644
index 0000000000..7cef0f39c3
--- /dev/null
+++ b/src/qmlcompiler/qqmljscompilerstats.cpp
@@ -0,0 +1,188 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qqmljscompilerstats_p.h"
+
+#include <QFile>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QTextStream>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+using namespace Qt::StringLiterals;
+
+std::unique_ptr<AotStats> QQmlJSAotCompilerStats::s_instance = std::make_unique<AotStats>();
+QString QQmlJSAotCompilerStats::s_moduleId;
+bool QQmlJSAotCompilerStats::s_recordAotStats = false;
+
+bool QQmlJS::AotStatsEntry::operator<(const AotStatsEntry &other) const
+{
+ if (line == other.line)
+ return column < other.column;
+ return line < other.line;
+}
+
+void AotStats::insert(const AotStats &other)
+{
+ for (const auto &[moduleUri, moduleStats] : other.m_entries.asKeyValueRange()) {
+ m_entries[moduleUri].insert(moduleStats);
+ }
+}
+
+std::optional<QList<QString>> extractAotstatsFilesList(const QString &aotstatsListPath)
+{
+ QFile aotstatsListFile(aotstatsListPath);
+ if (!aotstatsListFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qDebug().noquote() << u"Could not open \"%1\" for reading"_s.arg(aotstatsListFile.fileName());
+ return std::nullopt;
+ }
+
+ QStringList aotstatsFiles;
+ QTextStream stream(&aotstatsListFile);
+ while (!stream.atEnd())
+ aotstatsFiles.append(stream.readLine());
+
+ return aotstatsFiles;
+}
+
+std::optional<AotStats> AotStats::parseAotstatsFile(const QString &aotstatsPath)
+{
+ QFile file(aotstatsPath);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qDebug().noquote() << u"Could not open \"%1\""_s.arg(aotstatsPath);
+ return std::nullopt;
+ }
+
+ return AotStats::fromJsonDocument(QJsonDocument::fromJson(file.readAll()));
+}
+
+std::optional<AotStats> AotStats::aggregateAotstatsList(const QString &aotstatsListPath)
+{
+ const auto aotstatsFiles = extractAotstatsFilesList(aotstatsListPath);
+ if (!aotstatsFiles.has_value())
+ return std::nullopt;
+
+ AotStats aggregated;
+ if (aotstatsFiles->empty())
+ return aggregated;
+
+ for (const auto &aotstatsFile : aotstatsFiles.value()) {
+ auto parsed = parseAotstatsFile(aotstatsFile);
+ if (!parsed.has_value())
+ return std::nullopt;
+ aggregated.insert(parsed.value());
+ }
+
+ return aggregated;
+}
+
+AotStats AotStats::fromJsonDocument(const QJsonDocument &document)
+{
+ QJsonArray modulesArray = document.array();
+
+ QQmlJS::AotStats result;
+ for (const auto &modulesArrayEntry : modulesArray) {
+ const auto &moduleObject = modulesArrayEntry.toObject();
+ QString moduleId = moduleObject[u"moduleId"_s].toString();
+ const QJsonArray &filesArray = moduleObject[u"moduleFiles"_s].toArray();
+
+ QHash<QString, QList<AotStatsEntry>> files;
+ for (const auto &filesArrayEntry : filesArray) {
+ const QJsonObject &fileObject = filesArrayEntry.toObject();
+ QString filepath = fileObject[u"filepath"_s].toString();
+ const QJsonArray &statsArray = fileObject[u"entries"_s].toArray();
+
+ QList<AotStatsEntry> stats;
+ for (const auto &statsArrayEntry : statsArray) {
+ const auto &statsObject = statsArrayEntry.toObject();
+ QQmlJS::AotStatsEntry stat;
+ auto micros = statsObject[u"durationMicroseconds"_s].toInteger();
+ stat.codegenDuration = std::chrono::microseconds(micros);
+ stat.functionName = statsObject[u"functionName"_s].toString();
+ stat.errorMessage = statsObject[u"errorMessage"_s].toString();
+ stat.line = statsObject[u"line"_s].toInt();
+ stat.column = statsObject[u"column"_s].toInt();
+ stat.codegenSuccessful = statsObject[u"codegenSuccessfull"_s].toBool();
+ stats.append(std::move(stat));
+ }
+
+ std::sort(stats.begin(), stats.end());
+ files[filepath] = std::move(stats);
+ }
+
+ result.m_entries[moduleId] = std::move(files);
+ }
+
+ return result;
+}
+
+QJsonDocument AotStats::toJsonDocument() const
+{
+ QJsonArray modulesArray;
+ for (auto it1 = m_entries.begin(); it1 != m_entries.end(); ++it1) {
+ const QString moduleId = it1.key();
+ const QHash<QString, QList<AotStatsEntry>> &files = it1.value();
+
+ QJsonArray filesArray;
+ for (auto it2 = files.begin(); it2 != files.end(); ++it2) {
+ const QString &filename = it2.key();
+ const QList<AotStatsEntry> &stats = it2.value();
+
+ QJsonArray statsArray;
+ for (const auto &stat : stats) {
+ QJsonObject statObject;
+ auto micros = static_cast<qint64>(stat.codegenDuration.count());
+ statObject.insert(u"durationMicroseconds", micros);
+ statObject.insert(u"functionName", stat.functionName);
+ statObject.insert(u"errorMessage", stat.errorMessage);
+ statObject.insert(u"line", stat.line);
+ statObject.insert(u"column", stat.column);
+ statObject.insert(u"codegenSuccessfull", stat.codegenSuccessful);
+ statsArray.append(statObject);
+ }
+
+ QJsonObject o;
+ o.insert(u"filepath"_s, filename);
+ o.insert(u"entries"_s, statsArray);
+ filesArray.append(o);
+ }
+
+ QJsonObject o;
+ o.insert(u"moduleId"_s, moduleId);
+ o.insert(u"moduleFiles"_s, filesArray);
+ modulesArray.append(o);
+ }
+
+ return QJsonDocument(modulesArray);
+}
+
+void AotStats::addEntry(
+ const QString &moduleId, const QString &filepath, const AotStatsEntry &entry)
+{
+ m_entries[moduleId][filepath].append(entry);
+}
+
+bool AotStats::saveToDisk(const QString &filepath) const
+{
+ QFile file(filepath);
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
+ qDebug().noquote() << u"Could not open \"%1\""_s.arg(filepath);
+ return false;
+ }
+
+ file.write(this->toJsonDocument().toJson(QJsonDocument::Indented));
+ return true;
+}
+
+void QQmlJSAotCompilerStats::addEntry(const QString &filepath, const QQmlJS::AotStatsEntry &entry)
+{
+ QQmlJSAotCompilerStats::instance()->addEntry(s_moduleId, filepath, entry);
+}
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljscompilerstats_p.h b/src/qmlcompiler/qqmljscompilerstats_p.h
new file mode 100644
index 0000000000..53ebb9f777
--- /dev/null
+++ b/src/qmlcompiler/qqmljscompilerstats_p.h
@@ -0,0 +1,92 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QQMLJSCOMPILERSTATS_P_H
+#define QQMLJSCOMPILERSTATS_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 <qtqmlcompilerexports.h>
+
+#include <QHash>
+#include <QJsonDocument>
+
+#include <private/qqmljsdiagnosticmessage_p.h>
+#include <private/qqmljssourcelocation_p.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+struct Q_QMLCOMPILER_EXPORT AotStatsEntry
+{
+ std::chrono::microseconds codegenDuration;
+ QString functionName;
+ QString errorMessage;
+ int line = 0;
+ int column = 0;
+ bool codegenSuccessful = true;
+
+ bool operator<(const AotStatsEntry &) const;
+};
+
+class Q_QMLCOMPILER_EXPORT AotStats
+{
+ friend class QQmlJSAotCompilerStats;
+
+public:
+ const QHash<QString, QHash<QString, QList<AotStatsEntry>>> &entries() const
+ {
+ return m_entries;
+ }
+
+ void addEntry(const QString &moduleId, const QString &filepath, const AotStatsEntry &entry);
+ void insert(const AotStats &other);
+
+ bool saveToDisk(const QString &filepath) const;
+
+ static std::optional<AotStats> parseAotstatsFile(const QString &aotstatsPath);
+ static std::optional<AotStats> aggregateAotstatsList(const QString &aotstatsListPath);
+
+ static AotStats fromJsonDocument(const QJsonDocument &);
+ QJsonDocument toJsonDocument() const;
+
+private:
+ // module Id -> filename -> stats m_entries
+ QHash<QString, QHash<QString, QList<AotStatsEntry>>> m_entries;
+};
+
+class Q_QMLCOMPILER_EXPORT QQmlJSAotCompilerStats
+{
+public:
+ static AotStats *instance() { return s_instance.get(); }
+
+ static bool recordAotStats() { return s_recordAotStats; }
+ static void setRecordAotStats(bool recordAotStats) { s_recordAotStats = recordAotStats; }
+
+ static QString moduleId() { return s_moduleId; }
+ static void setModuleId(const QString &moduleId) { s_moduleId = moduleId; }
+
+ static void addEntry(const QString &filepath, const QQmlJS::AotStatsEntry &entry);
+
+private:
+ static std::unique_ptr<AotStats> s_instance;
+ static QString s_moduleId;
+ static bool s_recordAotStats;
+};
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QQMLJSCOMPILERSTATS_P_H
diff --git a/src/qmlcompiler/qqmljscompilerstatsreporter.cpp b/src/qmlcompiler/qqmljscompilerstatsreporter.cpp
new file mode 100644
index 0000000000..1cb17f71fe
--- /dev/null
+++ b/src/qmlcompiler/qqmljscompilerstatsreporter.cpp
@@ -0,0 +1,118 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qqmljscompilerstatsreporter_p.h"
+
+#include <QFileInfo>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+using namespace Qt::StringLiterals;
+
+AotStatsReporter::AotStatsReporter(const AotStats &aotstats) : m_aotstats(aotstats)
+{
+ for (const auto &[moduleUri, fileEntries] : aotstats.entries().asKeyValueRange()) {
+ for (const auto &[filepath, statsEntries] : fileEntries.asKeyValueRange()) {
+ for (const auto &entry : statsEntries) {
+ m_fileCounters[moduleUri][filepath].codegens += 1;
+ if (entry.codegenSuccessful) {
+ m_fileCounters[moduleUri][filepath].successes += 1;
+ m_successDurations.append(entry.codegenDuration);
+ }
+ }
+ m_moduleCounters[moduleUri].codegens += m_fileCounters[moduleUri][filepath].codegens;
+ m_moduleCounters[moduleUri].successes += m_fileCounters[moduleUri][filepath].successes;
+ }
+ m_totalCounters.codegens += m_moduleCounters[moduleUri].codegens;
+ m_totalCounters.successes += m_moduleCounters[moduleUri].successes;
+ }
+}
+
+void AotStatsReporter::formatDetailedStats(QTextStream &s) const
+{
+ s << "############ AOT COMPILATION STATS ############\n";
+ for (const auto &[moduleUri, fileStats] : m_aotstats.entries().asKeyValueRange()) {
+ s << u"Module %1:\n"_s.arg(moduleUri);
+ if (fileStats.empty()) {
+ s << "No attempts at compiling a binding or function\n";
+ continue;
+ }
+
+ for (const auto &[filename, entries] : fileStats.asKeyValueRange()) {
+ s << u"--File %1\n"_s.arg(filename);
+ if (entries.empty()) {
+ s << " No attempts at compiling a binding or function\n";
+ continue;
+ }
+
+ int successes = m_fileCounters[moduleUri][filename].successes;
+ s << " " << formatSuccessRate(entries.size(), successes) << "\n";
+
+ for (const auto &stat : entries) {
+ s << u" %1: [%2:%3:%4]\n"_s.arg(stat.functionName)
+ .arg(QFileInfo(filename).fileName())
+ .arg(stat.line)
+ .arg(stat.column);
+ s << u" result: "_s << (stat.codegenSuccessful
+ ? u"Success\n"_s
+ : u"Error: "_s + stat.errorMessage + u'\n');
+ s << u" duration: %1us\n"_s.arg(stat.codegenDuration.count());
+ }
+ s << "\n";
+ }
+ }
+}
+
+void AotStatsReporter::formatSummary(QTextStream &s) const
+{
+ s << "############ AOT COMPILATION STATS SUMMARY ############\n";
+ if (m_totalCounters.codegens == 0) {
+ s << "No attempted compilations to Cpp for bindings or functions.\n";
+ return;
+ }
+
+ for (const auto &moduleUri : m_aotstats.entries().keys()) {
+ const auto &counters = m_moduleCounters[moduleUri];
+ s << u"Module %1: "_s.arg(moduleUri)
+ << formatSuccessRate(counters.codegens, counters.successes) << "\n";
+ }
+
+ s << "Total results: " << formatSuccessRate(m_totalCounters.codegens, m_totalCounters.successes);
+ s << "\n";
+
+ if (m_totalCounters.successes != 0) {
+ auto totalDuration = std::accumulate(m_successDurations.cbegin(), m_successDurations.cend(),
+ std::chrono::microseconds(0));
+ const auto averageDuration = totalDuration.count() / m_totalCounters.successes;
+ s << u"Successful codegens took an average of %1us\n"_s.arg(averageDuration);
+ }
+}
+
+QString AotStatsReporter::format() const
+{
+ QString output;
+ QTextStream s(&output);
+
+ formatDetailedStats(s);
+ formatSummary(s);
+
+ return output;
+}
+
+QString AotStatsReporter::formatSuccessRate(int codegens, int successes) const
+{
+ if (codegens == 0)
+ return u"No attempted compilations"_s;
+
+ return u"%1 of %2 (%3%4) bindings or functions compiled to Cpp successfully"_s
+ .arg(successes)
+ .arg(codegens)
+ .arg(double(successes) / codegens * 100, 0, 'g', 4)
+ .arg(u"%"_s);
+}
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljscompilerstatsreporter_p.h b/src/qmlcompiler/qqmljscompilerstatsreporter_p.h
new file mode 100644
index 0000000000..9acf4adac8
--- /dev/null
+++ b/src/qmlcompiler/qqmljscompilerstatsreporter_p.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QQMLJSCOMPILERSTATSREPORTER_P_H
+#define QQMLJSCOMPILERSTATSREPORTER_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 <QTextStream>
+
+#include <qtqmlcompilerexports.h>
+
+#include <private/qqmljscompilerstats_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class Q_QMLCOMPILER_EXPORT AotStatsReporter
+{
+public:
+ AotStatsReporter(const QQmlJS::AotStats &);
+
+ QString format() const;
+
+private:
+ void formatDetailedStats(QTextStream &) const;
+ void formatSummary(QTextStream &) const;
+ QString formatSuccessRate(int codegens, int successes) const;
+
+ const AotStats &m_aotstats;
+
+ struct Counters
+ {
+ int successes = 0;
+ int codegens = 0;
+ };
+
+ Counters m_totalCounters;
+ QHash<QString, Counters> m_moduleCounters;
+ QHash<QString, QHash<QString, Counters>> m_fileCounters;
+ QList<std::chrono::microseconds> m_successDurations;
+};
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QQMLJSCOMPILERSTATSREPORTER_P_H
diff --git a/src/qmlcompiler/qqmljsfunctioninitializer.cpp b/src/qmlcompiler/qqmljsfunctioninitializer.cpp
index 09928364b1..a767da68b6 100644
--- a/src/qmlcompiler/qqmljsfunctioninitializer.cpp
+++ b/src/qmlcompiler/qqmljsfunctioninitializer.cpp
@@ -160,7 +160,7 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run(
bindingLocation.startColumn = irBinding.location.column();
QQmlJSCompilePass::Function function;
- function.qmlScope = m_scopeType;
+ function.qmlScope = m_typeResolver->globalType(m_scopeType);
if (irBinding.type() != QmlIR::Binding::Type_Script) {
diagnose(u"Binding is not a script binding, but %1."_s.arg(
@@ -270,7 +270,7 @@ QQmlJSCompilePass::Function QQmlJSFunctionInitializer::run(
Q_UNUSED(functionName);
QQmlJSCompilePass::Function function;
- function.qmlScope = m_scopeType;
+ function.qmlScope = m_typeResolver->globalType(m_scopeType);
auto ast = astNode->asFunctionDefinition();
Q_ASSERT(ast);
diff --git a/src/qmlcompiler/qqmljsimporter.cpp b/src/qmlcompiler/qqmljsimporter.cpp
index bcc8e98434..ae5d1654f0 100644
--- a/src/qmlcompiler/qqmljsimporter.cpp
+++ b/src/qmlcompiler/qqmljsimporter.cpp
@@ -616,24 +616,30 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
Import result;
result.name = QStringLiteral("QML");
- QStringList qmltypesFiles = { QStringLiteral("builtins.qmltypes"),
- QStringLiteral("jsroot.qmltypes") };
- const auto importBuiltins = [&](const QStringList &imports) {
+ const auto importBuiltins = [&](const QString &qmltypesFile, const QStringList &imports) {
for (auto const &dir : imports) {
- QDirIterator it { dir, qmltypesFiles, QDir::NoFilter };
- while (it.hasNext() && !qmltypesFiles.isEmpty()) {
- readQmltypes(it.next(), &result.objects, &result.dependencies);
- qmltypesFiles.removeOne(it.fileName());
- }
+ const QDir importDir(dir);
+ if (!importDir.exists(qmltypesFile))
+ continue;
+
+ readQmltypes(
+ importDir.filePath(qmltypesFile), &result.objects, &result.dependencies);
setQualifiedNamesOn(result);
importDependencies(result, &builtins);
-
- if (qmltypesFiles.isEmpty())
- return;
+ return true;
}
+
+ return false;
};
- importBuiltins(m_importPaths);
+ // If the same name (such as "Qt") appears in the JS root and in the builtins,
+ // we want the builtins to override the JS root. Therefore, process jsroot first.
+ QStringList qmltypesFiles;
+ for (QString qmltypesFile : { "jsroot.qmltypes"_L1, "builtins.qmltypes"_L1 }) {
+ if (!importBuiltins(qmltypesFile, m_importPaths))
+ qmltypesFiles.append(std::move(qmltypesFile));
+ }
+
if (!qmltypesFiles.isEmpty()) {
const QString pathsString =
m_importPaths.isEmpty() ? u"<empty>"_s : m_importPaths.join(u"\n\t");
@@ -641,9 +647,13 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
"qrc). Import paths used:\n\t%2")
.arg(qmltypesFiles.join(u", "), pathsString),
QtWarningMsg, QQmlJS::SourceLocation() });
- importBuiltins({ u":/qt-project.org/qml/builtins"_s }); // use qrc as a "last resort"
+
+ // use qrc as a "last resort"
+ for (const QString &qmltypesFile : std::as_const(qmltypesFiles)) {
+ const bool found = importBuiltins(qmltypesFile, { u":/qt-project.org/qml/builtins"_s });
+ Q_ASSERT(found); // since qrc must cover it in all the bad cases
+ }
}
- Q_ASSERT(qmltypesFiles.isEmpty()); // since qrc must cover it in all the bad cases
// Process them together since there they have interdependencies that wouldn't get resolved
// otherwise
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index f048748b58..bf9be59380 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -1589,6 +1589,7 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
UiParameterList *param = publicMember->parameters;
QQmlJSMetaMethod method;
method.setMethodType(QQmlJSMetaMethodType::Signal);
+ method.setReturnTypeName(QStringLiteral("void"));
method.setMethodName(publicMember->name.toString());
method.setSourceLocation(combine(publicMember->firstSourceLocation(),
publicMember->lastSourceLocation()));
diff --git a/src/qmlcompiler/qqmljslintercodegen.cpp b/src/qmlcompiler/qqmljslintercodegen.cpp
index 175f7ee1e0..60fc9cb5ad 100644
--- a/src/qmlcompiler/qqmljslintercodegen.cpp
+++ b/src/qmlcompiler/qqmljslintercodegen.cpp
@@ -6,6 +6,7 @@
#include <QtQmlCompiler/private/qqmljsimportvisitor_p.h>
#include <QtQmlCompiler/private/qqmljsshadowcheck_p.h>
#include <QtQmlCompiler/private/qqmljsstoragegeneralizer_p.h>
+#include <QtQmlCompiler/private/qqmljsstorageinitializer_p.h>
#include <QtQmlCompiler/private/qqmljstypepropagator_p.h>
#include <QtQmlCompiler/private/qqmljsfunctioninitializer_p.h>
@@ -92,6 +93,12 @@ bool QQmlJSLinterCodegen::analyzeFunction(const QV4::Compiler::Context *context,
}
if (!error->isValid()) {
+ QQmlJSStorageInitializer initializer(m_unitGenerator, &m_typeResolver, m_logger,
+ basicBlocks, annotations);
+ initializer.run(function, error);
+ }
+
+ if (!error->isValid()) {
QQmlJSStorageGeneralizer generalizer(m_unitGenerator, &m_typeResolver, m_logger,
basicBlocks, annotations);
generalizer.run(function, error);
diff --git a/src/qmlcompiler/qqmljsmetatypes_p.h b/src/qmlcompiler/qqmljsmetatypes_p.h
index 0ea7020a2d..f715f22ea7 100644
--- a/src/qmlcompiler/qqmljsmetatypes_p.h
+++ b/src/qmlcompiler/qqmljsmetatypes_p.h
@@ -373,8 +373,9 @@ class QQmlJSMetaProperty
bool m_isList = false;
bool m_isWritable = false;
bool m_isPointer = false;
+ bool m_isTypeConstant = false;
bool m_isFinal = false;
- bool m_isConstant = false;
+ bool m_isPropertyConstant = false;
int m_revision = 0;
int m_index = -1; // relative property index within owning QQmlJSScope
@@ -421,6 +422,9 @@ public:
void setIsPointer(bool isPointer) { m_isPointer = isPointer; }
bool isPointer() const { return m_isPointer; }
+ void setIsTypeConstant(bool isTypeConstant) { m_isTypeConstant = isTypeConstant; }
+ bool isTypeConstant() const { return m_isTypeConstant; }
+
void setAliasExpression(const QString &aliasString) { m_aliasExpr = aliasString; }
QString aliasExpression() const { return m_aliasExpr; }
bool isAlias() const { return !m_aliasExpr.isEmpty(); } // exists for convenience
@@ -428,8 +432,8 @@ public:
void setIsFinal(bool isFinal) { m_isFinal = isFinal; }
bool isFinal() const { return m_isFinal; }
- void setIsConstant(bool isConstant) { m_isConstant = isConstant; }
- bool isConstant() const { return m_isConstant; }
+ void setIsPropertyConstant(bool isPropertyConstant) { m_isPropertyConstant = isPropertyConstant; }
+ bool isPropertyConstant() const { return m_isPropertyConstant; }
void setRevision(int revision) { m_revision = revision; }
int revision() const { return m_revision; }
diff --git a/src/qmlcompiler/qqmljsoptimizations.cpp b/src/qmlcompiler/qqmljsoptimizations.cpp
index 1d0a7cf415..d542331be6 100644
--- a/src/qmlcompiler/qqmljsoptimizations.cpp
+++ b/src/qmlcompiler/qqmljsoptimizations.cpp
@@ -84,12 +84,8 @@ void QQmlJSOptimizations::populateReaderLocations()
it->second.changedRegister = QQmlJSRegisterContent();
} else {
// void the output, rather than deleting it. We still need its variant.
- bool adjusted = m_typeResolver->adjustTrackedType(
- it->second.changedRegister.storedType(), m_typeResolver->voidType());
- Q_ASSERT(adjusted); // Can always convert to void
-
- adjusted = m_typeResolver->adjustTrackedType(
- m_typeResolver->containedType(it->second.changedRegister),
+ const bool adjusted = m_typeResolver->adjustTrackedType(
+ it->second.changedRegister.containedType(),
m_typeResolver->voidType());
Q_ASSERT(adjusted); // Can always convert to void
}
@@ -127,6 +123,7 @@ void QQmlJSOptimizations::populateReaderLocations()
} else {
access.trackedTypes.append(
m_typeResolver->trackedContainedType(writeIt->second.changedRegister));
+ Q_ASSERT(!access.trackedTypes.last().isNull());
}
auto blockIt = QQmlJSBasicBlocks::basicBlockForInstruction(m_basicBlocks, writeIt.key());
@@ -314,13 +311,6 @@ void QQmlJSOptimizations::adjustTypes()
}
};
- const auto transformRegister = [&](const QQmlJSRegisterContent &content) {
- const QQmlJSScope::ConstPtr conversion
- = m_typeResolver->storedType(m_typeResolver->containedType(content));
- if (!m_typeResolver->adjustTrackedType(content.storedType(), conversion))
- setError(adjustErrorMessage(content.storedType(), conversion));
- };
-
// Handle the array definitions first.
// Changing the array type changes the expected element types.
auto adjustArray = [&](int instructionOffset, int mode) {
@@ -333,7 +323,7 @@ void QQmlJSOptimizations::adjustTypes()
return;
Q_ASSERT(it->trackedTypes.size() == 1);
- Q_ASSERT(it->trackedTypes[0] == m_typeResolver->containedType(annotation.changedRegister));
+ Q_ASSERT(it->trackedTypes[0] == annotation.changedRegister.containedType());
if (it->trackedTypes[0]->accessSemantics() != QQmlJSScope::AccessSemantics::Sequence)
return; // Constructed something else.
@@ -346,16 +336,13 @@ void QQmlJSOptimizations::adjustTypes()
// QQmlJSTypePropagator.
if (QQmlJSScope::ConstPtr valueType = it->trackedTypes[0]->valueType()) {
const QQmlJSRegisterContent content = annotation.readRegisters.begin().value().content;
- const QQmlJSScope::ConstPtr contained = m_typeResolver->containedType(content);
+ const QQmlJSScope::ConstPtr contained = content.containedType();
// If it's the 1-arg Array ctor, and the argument is a number, that's special.
if (mode != ObjectOrArrayDefinition::ArrayConstruct1ArgId
|| !m_typeResolver->equals(contained, m_typeResolver->realType())) {
if (!m_typeResolver->adjustTrackedType(contained, valueType))
setError(adjustErrorMessage(contained, valueType));
-
- // We still need to adjust the stored type, too.
- transformRegister(content);
}
}
@@ -375,7 +362,7 @@ void QQmlJSOptimizations::adjustTypes()
Q_ASSERT(it->trackedTypes.size() == 1);
QQmlJSScope::ConstPtr resultType = it->trackedTypes[0];
- Q_ASSERT(resultType == m_typeResolver->containedType(annotation.changedRegister));
+ Q_ASSERT(resultType == annotation.changedRegister.containedType());
Q_ASSERT(!annotation.readRegisters.isEmpty());
if (!m_typeResolver->adjustTrackedType(resultType, it->typeReaders.values()))
@@ -408,12 +395,9 @@ void QQmlJSOptimizations::adjustTypes()
continue;
}
const QQmlJSRegisterContent content = annotation.readRegisters[object.argv + i].content;
- const QQmlJSScope::ConstPtr contained = m_typeResolver->containedType(content);
+ const QQmlJSScope::ConstPtr contained = content.containedType();
if (!m_typeResolver->adjustTrackedType(contained, propType))
setError(adjustErrorMessage(contained, propType));
-
- // We still need to adjust the stored type, too.
- transformRegister(content);
}
// The others cannot be adjusted. We don't know their names, yet.
@@ -455,9 +439,6 @@ void QQmlJSOptimizations::adjustTypes()
NewVirtualRegisters newRegisters;
for (auto i = m_annotations.begin(), iEnd = m_annotations.end(); i != iEnd; ++i) {
- if (i->second.changedRegisterIndex != InvalidRegister)
- transformRegister(i->second.changedRegister);
-
for (auto conversion = i->second.typeConversions.begin(),
conversionEnd = i->second.typeConversions.end(); conversion != conversionEnd;
++conversion) {
@@ -474,7 +455,6 @@ void QQmlJSOptimizations::adjustTypes()
if (!m_typeResolver->adjustTrackedType(conversionResult, newResult))
setError(adjustErrorMessage(conversionResult, newResult));
}
- transformRegister(content);
newRegisters.appendOrdered(conversion);
}
i->second.typeConversions = newRegisters.take();
@@ -500,14 +480,7 @@ void QQmlJSOptimizations::populateBasicBlocks()
const InstructionAnnotation &instruction = instrIt->second;
for (auto it = instruction.readRegisters.begin(), end = instruction.readRegisters.end();
it != end; ++it) {
- if (!instruction.isRename) {
- Q_ASSERT(it->second.content.isConversion());
- for (const QQmlJSScope::ConstPtr &origin :
- it->second.content.conversionOrigins()) {
- if (!writtenTypes.contains(origin))
- block.readTypes.append(origin);
- }
- }
+ Q_ASSERT(instruction.isRename || it->second.content.isConversion());
if (!writtenRegisters.contains(it->first))
block.readRegisters.append(it->first);
}
@@ -522,7 +495,6 @@ void QQmlJSOptimizations::populateBasicBlocks()
}
}
- QQmlJSUtils::deduplicate(block.readTypes);
QQmlJSUtils::deduplicate(block.readRegisters);
}
}
diff --git a/src/qmlcompiler/qqmljsregistercontent.cpp b/src/qmlcompiler/qqmljsregistercontent.cpp
index 2c5d562e5b..8a135afe59 100644
--- a/src/qmlcompiler/qqmljsregistercontent.cpp
+++ b/src/qmlcompiler/qqmljsregistercontent.cpp
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qqmljsregistercontent_p.h"
-#include "qqmljstyperesolver_p.h"
QT_BEGIN_NAMESPACE
@@ -10,7 +9,7 @@ using namespace Qt::StringLiterals;
QString QQmlJSRegisterContent::descriptiveName() const
{
- if (m_storedType.isNull())
+ if (m_storedType.isNull() && containedType().isNull())
return u"(invalid type)"_s;
const auto scope = [this]() -> QString {
@@ -25,58 +24,80 @@ QString QQmlJSRegisterContent::descriptiveName() const
};
QString result;
- switch (m_content.index()) {
- case Type: {
- auto contained = std::get<std::pair<QQmlJSScope::ConstPtr, int>>(m_content).first;
+ switch (Kind(m_content.index())) {
+ case Kind::Type: {
+ const QQmlJSScope::ConstPtr contained = type();
result += contained->internalName();
- if (m_storedType->internalName() != contained->internalName())
+ if (m_storedType && m_storedType->internalName() != contained->internalName())
result += u" stored as "_s + m_storedType->internalName();
return result;
}
- case Property: {
- const QQmlJSMetaProperty prop = std::get<PropertyLookup>(m_content).property;
+ case Kind::Property: {
+ const QQmlJSMetaProperty prop = property();
result += scope() + prop.propertyName() + u" with type "_s + prop.typeName();
- if (m_storedType->internalName() != prop.typeName())
+ if (m_storedType && m_storedType->internalName() != prop.typeName())
result += u" (stored as "_s + m_storedType->internalName() + u")";
return result;
}
- case Method: {
- const auto methods = std::get<QList<QQmlJSMetaMethod>>(m_content);
+ case Kind::Method: {
+ const auto methods = method();
if (methods.isEmpty())
result = scope() + u"(unknown method)"_s;
else
result = scope() + methods[0].methodName() + u"(...)"_s;
- return result + u" (stored as "_s + m_storedType->internalName() + u")";
+ if (m_storedType)
+ return result + u" (stored as "_s + m_storedType->internalName() + u")";
+ return result;
}
- case Enum: {
- const auto e = std::get<std::pair<QQmlJSMetaEnum, QString>>(m_content);
- if (e.second.isEmpty())
- result = scope() + e.first.name();
+ case Kind::Enum: {
+ const QString enumName = enumeration().name();
+ const QString memberName = enumMember();
+ if (memberName.isEmpty())
+ result = scope() + enumName;
else
- result = scope() + e.first.name() + u"::"_s + e.second;
- return result + u" (stored as "_s + m_storedType->internalName() + u")";
+ result = scope() + enumName + u"::"_s + memberName;
+ if (m_storedType)
+ return result + u" (stored as "_s + m_storedType->internalName() + u")";
+ return result;
}
- case ImportNamespace: {
- return u"import namespace %1"_s.arg(std::get<uint>(m_content));
+ case Kind::ImportNamespace: {
+ return u"import namespace %1"_s.arg(importNamespace());
}
- case Conversion: {
- return u"conversion to %1"_s.arg(std::get<ConvertedTypes>(m_content).result->internalName());
+ case Kind::Conversion: {
+ return u"conversion to %1"_s.arg(conversionResult()->internalName());
}
}
Q_UNREACHABLE_RETURN(result + u"wat?"_s);
}
+QString QQmlJSRegisterContent::containedTypeName() const
+{
+ QQmlJSScope::ConstPtr type;
+
+ switch (variant()) {
+ case QQmlJSRegisterContent::MetaType:
+ type = scopeType();
+ break;
+ default:
+ type = containedType();
+ break;
+ }
+
+ return QQmlJSScope::prettyName(
+ type->internalName().isEmpty() ? type->baseTypeName() : type->internalName());
+}
+
bool QQmlJSRegisterContent::isList() const
{
- switch (m_content.index()) {
- case Type:
+ switch (Kind(m_content.index())) {
+ case Kind::Type:
return std::get<std::pair<QQmlJSScope::ConstPtr, int>>(m_content).first->accessSemantics()
== QQmlJSScope::AccessSemantics::Sequence;
- case Property:
+ case Kind::Property:
return std::get<PropertyLookup>(m_content).property.type()->accessSemantics()
== QQmlJSScope::AccessSemantics::Sequence;
- case Conversion:
+ case Kind::Conversion:
return std::get<ConvertedTypes>(m_content).result->accessSemantics()
== QQmlJSScope::AccessSemantics::Sequence;
default:
@@ -86,8 +107,8 @@ bool QQmlJSRegisterContent::isList() const
bool QQmlJSRegisterContent::isWritable() const
{
- switch (m_content.index()) {
- case Property:
+ switch (Kind(m_content.index())) {
+ case Kind::Property:
return std::get<PropertyLookup>(m_content).property.isWritable();
// TODO: What can we actually write?
@@ -98,67 +119,77 @@ bool QQmlJSRegisterContent::isWritable() const
return true;
}
-QQmlJSRegisterContent QQmlJSRegisterContent::create(const QQmlJSScope::ConstPtr &storedType,
- const QQmlJSScope::ConstPtr &type,
- int resultLookupIndex,
- QQmlJSRegisterContent::ContentVariant variant,
- const QQmlJSScope::ConstPtr &scope)
+QQmlJSScope::ConstPtr QQmlJSRegisterContent::containedType() const
+{
+ if (isType())
+ return type();
+ if (isProperty())
+ return property().type();
+ if (isEnumeration())
+ return enumeration().type();
+ if (isMethod())
+ return methodType();
+ if (isImportNamespace())
+ return importNamespaceType();
+ if (isConversion())
+ return conversionResult();
+
+ Q_UNREACHABLE_RETURN({});
+}
+
+QQmlJSRegisterContent QQmlJSRegisterContent::create(
+ const QQmlJSScope::ConstPtr &type, int resultLookupIndex,
+ QQmlJSRegisterContent::ContentVariant variant, const QQmlJSScope::ConstPtr &scope)
{
- QQmlJSRegisterContent result(storedType, scope, variant);
+ QQmlJSRegisterContent result(scope, variant);
result.m_content = std::make_pair(type, resultLookupIndex);
return result;
}
-QQmlJSRegisterContent QQmlJSRegisterContent::create(const QQmlJSScope::ConstPtr &storedType,
- const QQmlJSMetaProperty &property,
- int baseLookupIndex, int resultLookupIndex,
- QQmlJSRegisterContent::ContentVariant variant,
- const QQmlJSScope::ConstPtr &scope)
+QQmlJSRegisterContent QQmlJSRegisterContent::create(
+ const QQmlJSMetaProperty &property, int baseLookupIndex, int resultLookupIndex,
+ QQmlJSRegisterContent::ContentVariant variant, const QQmlJSScope::ConstPtr &scope)
{
- QQmlJSRegisterContent result(storedType, scope, variant);
+ QQmlJSRegisterContent result(scope, variant);
result.m_content = PropertyLookup { property, baseLookupIndex, resultLookupIndex};
return result;
}
-QQmlJSRegisterContent QQmlJSRegisterContent::create(const QQmlJSScope::ConstPtr &storedType,
- const QQmlJSMetaEnum &enumeration,
- const QString &enumMember,
- QQmlJSRegisterContent::ContentVariant variant,
- const QQmlJSScope::ConstPtr &scope)
+QQmlJSRegisterContent QQmlJSRegisterContent::create(
+ const QQmlJSMetaEnum &enumeration, const QString &enumMember,
+ QQmlJSRegisterContent::ContentVariant variant, const QQmlJSScope::ConstPtr &scope)
{
- QQmlJSRegisterContent result(storedType, scope, variant);
+ QQmlJSRegisterContent result(scope, variant);
result.m_content = std::make_pair(enumeration, enumMember);
return result;
}
-QQmlJSRegisterContent QQmlJSRegisterContent::create(const QQmlJSScope::ConstPtr &storedType,
- const QList<QQmlJSMetaMethod> &methods,
- QQmlJSRegisterContent::ContentVariant variant,
- const QQmlJSScope::ConstPtr &scope)
+QQmlJSRegisterContent QQmlJSRegisterContent::create(
+ const QList<QQmlJSMetaMethod> &methods, const QQmlJSScope::ConstPtr &methodType,
+ QQmlJSRegisterContent::ContentVariant variant, const QQmlJSScope::ConstPtr &scope)
{
- QQmlJSRegisterContent result(storedType, scope, variant);
- result.m_content = methods;
+ // Methods can only be stored in QJSValue.
+ Q_ASSERT(methodType->internalName() == u"QJSValue"_s);
+ QQmlJSRegisterContent result(scope, variant);
+ result.m_content = std::make_pair(methods, methodType);
return result;
}
-QQmlJSRegisterContent QQmlJSRegisterContent::create(const QQmlJSScope::ConstPtr &storedType,
- uint importNamespaceStringId,
- QQmlJSRegisterContent::ContentVariant variant,
- const QQmlJSScope::ConstPtr &scope)
+QQmlJSRegisterContent QQmlJSRegisterContent::create(
+ uint importNamespaceStringId, const QQmlJSScope::ConstPtr &importNamespaceType,
+ QQmlJSRegisterContent::ContentVariant variant, const QQmlJSScope::ConstPtr &scope)
{
- QQmlJSRegisterContent result(storedType, scope, variant);
- result.m_content = importNamespaceStringId;
+ QQmlJSRegisterContent result(scope, variant);
+ result.m_content = std::make_pair(importNamespaceStringId, importNamespaceType);
return result;
}
-QQmlJSRegisterContent QQmlJSRegisterContent::create(const QQmlJSScope::ConstPtr &storedType,
- const QList<QQmlJSScope::ConstPtr> &origins,
- const QQmlJSScope::ConstPtr &conversion,
- const QQmlJSScope::ConstPtr &conversionScope,
- ContentVariant variant,
- const QQmlJSScope::ConstPtr &scope)
+QQmlJSRegisterContent QQmlJSRegisterContent::create(
+ const QList<QQmlJSScope::ConstPtr> &origins, const QQmlJSScope::ConstPtr &conversion,
+ const QQmlJSScope::ConstPtr &conversionScope, ContentVariant variant,
+ const QQmlJSScope::ConstPtr &scope)
{
- QQmlJSRegisterContent result(storedType, scope, variant);
+ QQmlJSRegisterContent result(scope, variant);
result.m_content = ConvertedTypes { origins, conversion, conversionScope };
return result;
}
diff --git a/src/qmlcompiler/qqmljsregistercontent_p.h b/src/qmlcompiler/qqmljsregistercontent_p.h
index bbf5008399..00e28bc087 100644
--- a/src/qmlcompiler/qqmljsregistercontent_p.h
+++ b/src/qmlcompiler/qqmljsregistercontent_p.h
@@ -64,9 +64,10 @@ public:
enum { InvalidLookupIndex = -1 };
QQmlJSRegisterContent() = default;
- bool isValid() const { return !m_storedType.isNull(); }
+ bool isValid() const { return !containedType().isNull(); }
QString descriptiveName() const;
+ QString containedTypeName() const;
friend bool operator==(const QQmlJSRegisterContent &a, const QQmlJSRegisterContent &b)
{
@@ -79,17 +80,18 @@ public:
return !(a == b);
}
- bool isType() const { return m_content.index() == Type; }
- bool isProperty() const { return m_content.index() == Property; }
- bool isEnumeration() const { return m_content.index() == Enum; }
- bool isMethod() const { return m_content.index() == Method; }
- bool isImportNamespace() const { return m_content.index() == ImportNamespace; }
- bool isConversion() const { return m_content.index() == Conversion; }
+ bool isType() const { return m_content.index() == size_t(Kind::Type); }
+ bool isProperty() const { return m_content.index() == size_t(Kind::Property); }
+ bool isEnumeration() const { return m_content.index() == size_t(Kind::Enum); }
+ bool isMethod() const { return m_content.index() == size_t(Kind::Method); }
+ bool isImportNamespace() const { return m_content.index() == size_t(Kind::ImportNamespace); }
+ bool isConversion() const { return m_content.index() == size_t(Kind::Conversion); }
bool isList() const;
bool isWritable() const;
QQmlJSScope::ConstPtr storedType() const { return m_storedType; }
+ QQmlJSScope::ConstPtr containedType() const;
QQmlJSScope::ConstPtr scopeType() const { return m_scope; }
QQmlJSScope::ConstPtr type() const
@@ -106,10 +108,10 @@ public:
}
int resultLookupIndex() const
{
- switch (m_content.index()) {
- case Type:
+ switch (Kind(m_content.index())) {
+ case Kind::Type:
return std::get<std::pair<QQmlJSScope::ConstPtr, int>>(m_content).second;
- case Property:
+ case Kind::Property:
return std::get<PropertyLookup>(m_content).resultLookupIndex;
default:
return InvalidLookupIndex;
@@ -123,8 +125,24 @@ public:
{
return std::get<std::pair<QQmlJSMetaEnum, QString>>(m_content).second;
}
- QList<QQmlJSMetaMethod> method() const { return std::get<QList<QQmlJSMetaMethod>>(m_content); }
- uint importNamespace() const { return std::get<uint>(m_content); }
+ QList<QQmlJSMetaMethod> method() const
+ {
+ return std::get<std::pair<QList<QQmlJSMetaMethod>, QQmlJSScope::ConstPtr>>(
+ m_content).first;
+ }
+ QQmlJSScope::ConstPtr methodType() const
+ {
+ return std::get<std::pair<QList<QQmlJSMetaMethod>, QQmlJSScope::ConstPtr>>(
+ m_content).second;
+ }
+ uint importNamespace() const
+ {
+ return std::get<std::pair<uint, QQmlJSScope::ConstPtr>>(m_content).first;
+ }
+ QQmlJSScope::ConstPtr importNamespaceType() const
+ {
+ return std::get<std::pair<uint, QQmlJSScope::ConstPtr>>(m_content).second;
+ }
QQmlJSScope::ConstPtr conversionResult() const
{
@@ -147,53 +165,52 @@ public:
{
seed = qHashMulti(seed, registerContent.m_storedType, registerContent.m_content.index(),
registerContent.m_scope, registerContent.m_variant);
- switch (registerContent.m_content.index()) {
- case Type:
+ switch (Kind(registerContent.m_content.index())) {
+ case Kind::Type:
return qHash(std::get<std::pair<QQmlJSScope::ConstPtr, int>>(registerContent.m_content),
seed);
- case Property:
+ case Kind::Property:
return qHash(std::get<PropertyLookup>(registerContent.m_content), seed);
- case Enum:
+ case Kind::Enum:
return qHash(std::get<std::pair<QQmlJSMetaEnum, QString>>(registerContent.m_content),
seed);
- case Method:
- return qHash(std::get<QList<QQmlJSMetaMethod>>(registerContent.m_content), seed);
- case ImportNamespace:
- return qHash(std::get<uint>(registerContent.m_content), seed);
- case Conversion:
+ case Kind::Method:
+ return qHash(std::get<std::pair<QList<QQmlJSMetaMethod>, QQmlJSScope::ConstPtr>>(
+ registerContent.m_content), seed);
+ case Kind::ImportNamespace:
+ return qHash(std::get<std::pair<uint, QQmlJSScope::ConstPtr>>(
+ registerContent.m_content), seed);
+ case Kind::Conversion:
return qHash(std::get<ConvertedTypes>(registerContent.m_content), seed);
}
Q_UNREACHABLE_RETURN(seed);
}
- static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &storedType,
- const QQmlJSScope::ConstPtr &type,
+ static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &type,
int resultLookupIndex, ContentVariant variant,
const QQmlJSScope::ConstPtr &scope = {});
- static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &storedType,
- const QQmlJSMetaProperty &property,
+ static QQmlJSRegisterContent create(const QQmlJSMetaProperty &property,
int baseLookupIndex, int resultLookupIndex,
ContentVariant variant,
const QQmlJSScope::ConstPtr &scope);
- static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &storedType,
- const QQmlJSMetaEnum &enumeration,
+ static QQmlJSRegisterContent create(const QQmlJSMetaEnum &enumeration,
const QString &enumMember, ContentVariant variant,
const QQmlJSScope::ConstPtr &scope);
- static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &storedType,
- const QList<QQmlJSMetaMethod> &methods,
+ static QQmlJSRegisterContent create(const QList<QQmlJSMetaMethod> &methods,
+ const QQmlJSScope::ConstPtr &methodType,
ContentVariant variant,
const QQmlJSScope::ConstPtr &scope);
- static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &storedType,
- uint importNamespaceStringId, ContentVariant variant,
+ static QQmlJSRegisterContent create(uint importNamespaceStringId,
+ const QQmlJSScope::ConstPtr &importNamespaceType,
+ ContentVariant variant,
const QQmlJSScope::ConstPtr &scope = {});
- static QQmlJSRegisterContent create(const QQmlJSScope::ConstPtr &storedType,
- const QList<QQmlJSScope::ConstPtr> &origins,
+ static QQmlJSRegisterContent create(const QList<QQmlJSScope::ConstPtr> &origins,
const QQmlJSScope::ConstPtr &conversion,
const QQmlJSScope::ConstPtr &conversionScope,
ContentVariant variant,
@@ -215,7 +232,7 @@ public:
}
private:
- enum ContentKind { Type, Property, Enum, Method, ImportNamespace, Conversion };
+ enum class Kind : size_t { Type, Property, Enum, Method, ImportNamespace, Conversion };
struct ConvertedTypes
{
@@ -268,14 +285,13 @@ private:
std::pair<QQmlJSScope::ConstPtr, int>,
PropertyLookup,
std::pair<QQmlJSMetaEnum, QString>,
- QList<QQmlJSMetaMethod>,
- uint,
+ std::pair<QList<QQmlJSMetaMethod>, QQmlJSScope::ConstPtr>,
+ std::pair<uint, QQmlJSScope::ConstPtr>,
ConvertedTypes
>;
- QQmlJSRegisterContent(const QQmlJSScope::ConstPtr &storedType,
- const QQmlJSScope::ConstPtr &scope, ContentVariant variant)
- : m_storedType(storedType), m_scope(scope), m_variant(variant)
+ QQmlJSRegisterContent(const QQmlJSScope::ConstPtr &scope, ContentVariant variant)
+ : m_scope(scope), m_variant(variant)
{
}
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index b32f86226e..535134072f 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -1143,12 +1143,27 @@ bool QQmlJSScope::Export::isValid() const
return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty();
}
+QDeferredFactory<QQmlJSScope>::QDeferredFactory(QQmlJSImporter *importer, const QString &filePath,
+ const TypeReader &typeReader)
+ : m_filePath(filePath),
+ m_importer(importer),
+ m_typeReader(typeReader ? typeReader
+ : [](QQmlJSImporter *importer, const QString &filePath,
+ const QSharedPointer<QQmlJSScope> &scopeToPopulate) {
+ QQmlJSTypeReader defaultTypeReader(importer, filePath);
+ defaultTypeReader(scopeToPopulate);
+ return defaultTypeReader.errors();
+ })
+{
+}
+
void QDeferredFactory<QQmlJSScope>::populate(const QSharedPointer<QQmlJSScope> &scope) const
{
scope->setOwnModuleName(m_moduleName);
- QQmlJSTypeReader typeReader(m_importer, m_filePath);
- typeReader(scope);
- m_importer->m_globalWarnings.append(typeReader.errors());
+
+ QList<QQmlJS::DiagnosticMessage> errors = m_typeReader(m_importer, m_filePath, scope);
+ m_importer->m_globalWarnings.append(errors);
+
scope->setInternalName(internalName());
QQmlJSScope::resolveEnums(scope, m_importer->builtinInternalNames());
QQmlJSScope::resolveList(scope, m_importer->builtinInternalNames().arrayType());
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index 97ec6cc004..b0bc6818a3 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -641,11 +641,13 @@ template<>
class Q_QMLCOMPILER_EXPORT QDeferredFactory<QQmlJSScope>
{
public:
+ using TypeReader = std::function<QList<QQmlJS::DiagnosticMessage>(
+ QQmlJSImporter *importer, const QString &filePath,
+ const QSharedPointer<QQmlJSScope> &scopeToPopulate)>;
QDeferredFactory() = default;
- QDeferredFactory(QQmlJSImporter *importer, const QString &filePath) :
- m_filePath(filePath), m_importer(importer)
- {}
+ QDeferredFactory(QQmlJSImporter *importer, const QString &filePath,
+ const TypeReader &typeReader = {});
bool isValid() const
{
@@ -657,6 +659,10 @@ public:
return QFileInfo(m_filePath).baseName();
}
+ QString filePath() const { return m_filePath; }
+
+ QQmlJSImporter* importer() const { return m_importer; }
+
void setIsSingleton(bool isSingleton)
{
m_isSingleton = isSingleton;
@@ -677,6 +683,7 @@ private:
QQmlJSImporter *m_importer = nullptr;
bool m_isSingleton = false;
QString m_moduleName;
+ TypeReader m_typeReader;
};
using QQmlJSExportedScope = QQmlJSScope::ExportedScope<QQmlJSScope::Ptr>;
diff --git a/src/qmlcompiler/qqmljsshadowcheck.cpp b/src/qmlcompiler/qqmljsshadowcheck.cpp
index d542767dce..29de04e2f1 100644
--- a/src/qmlcompiler/qqmljsshadowcheck.cpp
+++ b/src/qmlcompiler/qqmljsshadowcheck.cpp
@@ -154,7 +154,7 @@ QQmlJSShadowCheck::Shadowability QQmlJSShadowCheck::checkShadowing(
else
m_baseTypes.append(baseType);
- if (baseType.storedType()->accessSemantics() != QQmlJSScope::AccessSemantics::Reference)
+ if (!baseType.containedType()->isReferenceType())
return NotShadowable;
switch (baseType.variant()) {
@@ -193,9 +193,7 @@ QQmlJSShadowCheck::Shadowability QQmlJSShadowCheck::checkShadowing(
if (currentAnnotation.changedRegisterIndex != InvalidRegister) {
m_typeResolver->adjustOriginalType(
- currentAnnotation.changedRegister.storedType(), varType);
- m_typeResolver->adjustOriginalType(
- m_typeResolver->containedType(currentAnnotation.changedRegister), varType);
+ currentAnnotation.changedRegister.containedType(), varType);
m_adjustedTypes.insert(currentAnnotation.changedRegister);
}
diff --git a/src/qmlcompiler/qqmljsstoragegeneralizer.cpp b/src/qmlcompiler/qqmljsstoragegeneralizer.cpp
index 937c35ddcd..3ba709b21f 100644
--- a/src/qmlcompiler/qqmljsstoragegeneralizer.cpp
+++ b/src/qmlcompiler/qqmljsstoragegeneralizer.cpp
@@ -22,6 +22,7 @@ QT_BEGIN_NAMESPACE
QQmlJSCompilePass::BlocksAndAnnotations
QQmlJSStorageGeneralizer::run(Function *function, QQmlJS::DiagnosticMessage *error)
{
+ m_function = function;
m_error = error;
if (QQmlJSRegisterContent &returnType = function->returnType; returnType.isValid()) {
diff --git a/src/qmlcompiler/qqmljsstorageinitializer.cpp b/src/qmlcompiler/qqmljsstorageinitializer.cpp
new file mode 100644
index 0000000000..b0f7d1a49f
--- /dev/null
+++ b/src/qmlcompiler/qqmljsstorageinitializer.cpp
@@ -0,0 +1,81 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qqmljsstorageinitializer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ * \internal
+ * \class QQmlJSStorageInitializer
+ *
+ * The QQmlJSStorageInitializer is a compile pass that initializes the storage
+ * for all register contents.
+ *
+ * QQmlJSStorageInitializer does not have to use the byte code at all but
+ * operates only on the annotations and the function description.
+ */
+
+QQmlJSCompilePass::BlocksAndAnnotations
+QQmlJSStorageInitializer::run(Function *function, QQmlJS::DiagnosticMessage *error)
+{
+ m_function = function;
+ m_error = error;
+
+ if (QQmlJSRegisterContent &returnType = function->returnType; returnType.isValid()) {
+ if (const QQmlJSScope::ConstPtr stored
+ = m_typeResolver->storedType(returnType.containedType())) {
+ returnType = returnType.storedIn(m_typeResolver->trackedType(stored));
+ } else {
+ setError(QStringLiteral("Cannot store the return type %1.")
+ .arg(returnType.containedType()->internalName()));
+ return {};
+ }
+ }
+
+ const auto storeRegister = [&](QQmlJSRegisterContent &content) {
+ if (!content.isValid())
+ return;
+
+ const QQmlJSScope::ConstPtr original
+ = m_typeResolver->originalType(content.containedType());
+ const QQmlJSScope::ConstPtr originalStored = m_typeResolver->storedType(original);
+ const QQmlJSScope::ConstPtr originalTracked = m_typeResolver->trackedType(originalStored);
+ content = content.storedIn(originalTracked);
+
+ const QQmlJSScope::ConstPtr adjustedStored
+ = m_typeResolver->storedType(content.containedType());
+
+ if (!m_typeResolver->adjustTrackedType(originalTracked, adjustedStored)) {
+ setError(QStringLiteral("Cannot adjust stored type for %1.")
+ .arg(content.containedType()->internalName()));
+ }
+ };
+
+ const auto storeRegisters = [&](VirtualRegisters &registers) {
+ for (auto j = registers.begin(), jEnd = registers.end(); j != jEnd; ++j)
+ storeRegister(j.value().content);
+ };
+
+ storeRegister(function->qmlScope);
+
+ for (QQmlJSRegisterContent &argument : function->argumentTypes) {
+ Q_ASSERT(argument.isValid());
+ storeRegister(argument);
+ }
+
+ for (QQmlJSRegisterContent &argument : function->registerTypes) {
+ Q_ASSERT(argument.isValid());
+ storeRegister(argument);
+ }
+
+ for (auto i = m_annotations.begin(), iEnd = m_annotations.end(); i != iEnd; ++i) {
+ storeRegister(i->second.changedRegister);
+ storeRegisters(i->second.typeConversions);
+ storeRegisters(i->second.readRegisters);
+ }
+
+ return { std::move(m_basicBlocks), std::move(m_annotations) };
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljsstorageinitializer_p.h b/src/qmlcompiler/qqmljsstorageinitializer_p.h
new file mode 100644
index 0000000000..0644807543
--- /dev/null
+++ b/src/qmlcompiler/qqmljsstorageinitializer_p.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QQMLJSSTORAGEINITIALIZER_P_H
+#define QQMLJSSTORAGEINITIALIZER_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/qqmljscompilepass_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QMLCOMPILER_EXPORT QQmlJSStorageInitializer : public QQmlJSCompilePass
+{
+public:
+ QQmlJSStorageInitializer(const QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
+ const QQmlJSTypeResolver *typeResolver, QQmlJSLogger *logger,
+ BasicBlocks basicBlocks, InstructionAnnotations annotations)
+ : QQmlJSCompilePass(jsUnitGenerator, typeResolver, logger, basicBlocks, annotations)
+ {}
+
+ BlocksAndAnnotations run(Function *function, QQmlJS::DiagnosticMessage *error);
+
+protected:
+ // We don't have to use the byte code here. We only transform the instruction annotations.
+ Verdict startInstruction(QV4::Moth::Instr::Type) override { return SkipInstruction; }
+ void endInstruction(QV4::Moth::Instr::Type) override {}
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLJSSTORAGEINITIALIZER_P_H
diff --git a/src/qmlcompiler/qqmljstypedescriptionreader.cpp b/src/qmlcompiler/qqmljstypedescriptionreader.cpp
index bebc01a8ef..b398137a23 100644
--- a/src/qmlcompiler/qqmljstypedescriptionreader.cpp
+++ b/src/qmlcompiler/qqmljstypedescriptionreader.cpp
@@ -324,7 +324,7 @@ void QQmlJSTypeDescriptionReader::readSignalOrMethod(
auto metaReturnType = metaMethod.returnValue();
metaReturnType.setIsPointer(readBoolBinding(script));
metaMethod.setReturnValue(metaReturnType);
- } else if (name == QLatin1String("isConstant")) {
+ } else if (name == QLatin1String("isTypeConstant")) {
auto metaReturnType = metaMethod.returnValue();
metaReturnType.setTypeQualifier(readBoolBinding(script)
? QQmlJSMetaParameter::Const
@@ -332,7 +332,7 @@ void QQmlJSTypeDescriptionReader::readSignalOrMethod(
metaMethod.setReturnValue(metaReturnType);
} else {
addWarning(script->firstSourceLocation(),
- tr("Expected only name, type, revision, isPointer, isConstant, "
+ tr("Expected only name, type, revision, isPointer, isTypeConstant, "
"isList, isCloned, isConstructor, and isJavaScriptFunction "
"in script bindings."));
}
@@ -348,6 +348,9 @@ void QQmlJSTypeDescriptionReader::readSignalOrMethod(
return;
}
+ if (metaMethod.returnTypeName().isEmpty())
+ metaMethod.setReturnTypeName(QLatin1String("void"));
+
scope->addOwnMethod(metaMethod);
}
@@ -380,8 +383,10 @@ void QQmlJSTypeDescriptionReader::readProperty(UiObjectDefinition *ast, const QQ
property.setIsList(readBoolBinding(script));
} else if (id == QLatin1String("isFinal")) {
property.setIsFinal(readBoolBinding(script));
- } else if (id == QLatin1String("isConstant")) {
- property.setIsConstant(readBoolBinding(script));
+ } else if (id == QLatin1String("isTypeConstant")) {
+ property.setIsTypeConstant(readBoolBinding(script));
+ } else if (id == QLatin1String("isPropertyConstant")) {
+ property.setIsPropertyConstant(readBoolBinding(script));
} else if (id == QLatin1String("revision")) {
property.setRevision(readIntBinding(script));
} else if (id == QLatin1String("bindable")) {
@@ -400,8 +405,8 @@ void QQmlJSTypeDescriptionReader::readProperty(UiObjectDefinition *ast, const QQ
property.setPrivateClass(readStringBinding(script));
} else {
addWarning(script->firstSourceLocation(),
- tr("Expected only type, name, revision, isPointer, isReadonly, isRequired, "
- "isFinal, isList, bindable, read, write, reset, notify, index, and "
+ tr("Expected only type, name, revision, isPointer, isTypeConstant, isReadonly, isRequired, "
+ "isFinal, isList, bindable, read, write, isPropertyConstant, reset, notify, index, and "
"privateClass and script bindings."));
}
}
@@ -474,7 +479,7 @@ void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSM
type = readStringBinding(script);
} else if (id == QLatin1String("isPointer")) {
isPointer = readBoolBinding(script);
- } else if (id == QLatin1String("isConstant")) {
+ } else if (id == QLatin1String("isTypeConstant")) {
isConstant = readBoolBinding(script);
} else if (id == QLatin1String("isReadonly")) {
// ### unhandled
@@ -482,7 +487,7 @@ void QQmlJSTypeDescriptionReader::readParameter(UiObjectDefinition *ast, QQmlJSM
isList = readBoolBinding(script);
} else {
addWarning(script->firstSourceLocation(),
- tr("Expected only name, type, isPointer, isConstant, isReadonly, "
+ tr("Expected only name, type, isPointer, isTypeConstant, isReadonly, "
"or IsList script bindings."));
}
}
diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp
index d7a7d68d9f..607ba71bab 100644
--- a/src/qmlcompiler/qqmljstypepropagator.cpp
+++ b/src/qmlcompiler/qqmljstypepropagator.cpp
@@ -78,9 +78,10 @@ void QQmlJSTypePropagator::generate_ret_SAcheck()
if (!m_function->isProperty)
return;
QQmlSA::PassManagerPrivate::get(m_passManager)
- ->analyzeBinding(QQmlJSScope::createQQmlSAElement(m_function->qmlScope),
+ ->analyzeBinding(QQmlJSScope::createQQmlSAElement(
+ m_function->qmlScope.containedType()),
QQmlJSScope::createQQmlSAElement(
- m_typeResolver->containedType(m_state.accumulatorIn())),
+ m_state.accumulatorIn().containedType()),
QQmlSA::SourceLocationPrivate::createQQmlSASourceLocation(
getCurrentBindingSourceLocation()));
}
@@ -101,7 +102,7 @@ void QQmlJSTypePropagator::generate_Ret()
if (m_function->isFullyTyped) {
// Do not complain if the function didn't have a valid annotation in the first place.
m_logger->log(u"Function without return type annotation returns %1"_s.arg(
- m_typeResolver->containedTypeName(m_state.accumulatorIn(), true)),
+ m_state.accumulatorIn().containedTypeName()),
qmlIncompatibleType, getCurrentBindingSourceLocation());
}
return;
@@ -111,8 +112,8 @@ void QQmlJSTypePropagator::generate_Ret()
m_returnType.descriptiveName()));
m_logger->log(u"Cannot assign binding of type %1 to %2"_s.arg(
- m_typeResolver->containedTypeName(m_state.accumulatorIn(), true),
- m_typeResolver->containedTypeName(m_returnType, true)),
+ m_state.accumulatorIn().containedTypeName(),
+ m_returnType.containedTypeName()),
qmlIncompatibleType, getCurrentBindingSourceLocation());
return;
}
@@ -296,27 +297,28 @@ void QQmlJSTypePropagator::handleUnqualifiedAccess(const QString &name, bool isM
{
auto location = getCurrentSourceLocation();
- if (m_function->qmlScope->isInCustomParserParent()) {
+ const auto qmlScopeContained = m_function->qmlScope.containedType();
+ if (qmlScopeContained->isInCustomParserParent()) {
// Only ignore custom parser based elements if it's not Connections.
- if (m_function->qmlScope->baseType().isNull()
- || m_function->qmlScope->baseType()->internalName() != u"QQmlConnections"_s)
+ if (qmlScopeContained->baseType().isNull()
+ || qmlScopeContained->baseType()->internalName() != u"QQmlConnections"_s)
return;
}
if (isMethod) {
- if (isCallingProperty(m_function->qmlScope, name))
+ if (isCallingProperty(qmlScopeContained, name))
return;
- } else if (propertyResolution(m_function->qmlScope, name) != PropertyMissing) {
+ } else if (propertyResolution(qmlScopeContained, name) != PropertyMissing) {
return;
}
std::optional<QQmlJSFixSuggestion> suggestion;
- auto childScopes = m_function->qmlScope->childScopes();
- for (qsizetype i = 0; i < m_function->qmlScope->childScopes().size(); i++) {
+ const auto childScopes = m_function->qmlScope.containedType()->childScopes();
+ for (qsizetype i = 0, end = childScopes.size(); i < end; i++) {
auto &scope = childScopes[i];
if (location.offset > scope->sourceLocation().offset) {
- if (i + 1 < childScopes.size()
+ if (i + 1 < end
&& childScopes.at(i + 1)->sourceLocation().offset < location.offset)
continue;
if (scope->childScopes().size() == 0)
@@ -361,18 +363,19 @@ void QQmlJSTypePropagator::handleUnqualifiedAccess(const QString &name, bool isM
// This heuristic does not recognize all instances of this occurring but should be sufficient
// protection against wrongly suggesting to add an id to the view to access the model that way
// which is very misleading
+ const auto qmlScope = m_function->qmlScope.containedType();
if (name == u"model" || name == u"index") {
- if (QQmlJSScope::ConstPtr parent = m_function->qmlScope->parentScope(); !parent.isNull()) {
+ if (const QQmlJSScope::ConstPtr parent = qmlScope->parentScope(); !parent.isNull()) {
const auto bindings = parent->ownPropertyBindings(u"delegate"_s);
for (auto it = bindings.first; it != bindings.second; it++) {
if (!it->hasObject())
continue;
- if (it->objectType() == m_function->qmlScope) {
+ if (it->objectType() == qmlScope) {
suggestion = QQmlJSFixSuggestion {
name + " is implicitly injected into this delegate."
" Add a required property instead."_L1,
- m_function->qmlScope->sourceLocation()
+ qmlScope->sourceLocation()
};
};
@@ -382,10 +385,9 @@ void QQmlJSTypePropagator::handleUnqualifiedAccess(const QString &name, bool isM
}
if (!suggestion.has_value()) {
- for (QQmlJSScope::ConstPtr scope = m_function->qmlScope; !scope.isNull();
- scope = scope->parentScope()) {
+ for (QQmlJSScope::ConstPtr scope = qmlScope; !scope.isNull(); scope = scope->parentScope()) {
if (scope->hasProperty(name)) {
- const QString id = m_function->addressableScopes.id(scope, m_function->qmlScope);
+ const QString id = m_function->addressableScopes.id(scope, qmlScope);
QQmlJS::SourceLocation fixLocation = location;
fixLocation.length = 0;
@@ -419,10 +421,9 @@ void QQmlJSTypePropagator::handleUnqualifiedAccess(const QString &name, bool isM
if (!suggestion.has_value()) {
if (auto didYouMean =
- QQmlJSUtils::didYouMean(name,
- m_function->qmlScope->properties().keys()
- + m_function->qmlScope->methods().keys(),
- location);
+ QQmlJSUtils::didYouMean(
+ name, qmlScope->properties().keys() + qmlScope->methods().keys(),
+ location);
didYouMean.has_value()) {
suggestion = didYouMean;
}
@@ -551,9 +552,10 @@ bool QQmlJSTypePropagator::isCallingProperty(QQmlJSScope::ConstPtr scope, const
void QQmlJSTypePropagator::generate_LoadQmlContextPropertyLookup_SAcheck(const QString &name)
{
+ const auto qmlScope = m_function->qmlScope.containedType();
QQmlSA::PassManagerPrivate::get(m_passManager)->analyzeRead(
- QQmlJSScope::createQQmlSAElement(m_function->qmlScope), name,
- QQmlJSScope::createQQmlSAElement(m_function->qmlScope),
+ QQmlJSScope::createQQmlSAElement(qmlScope), name,
+ QQmlJSScope::createQQmlSAElement(qmlScope),
QQmlSA::SourceLocationPrivate::createQQmlSASourceLocation(
getCurrentBindingSourceLocation()));
}
@@ -569,15 +571,16 @@ void QQmlJSTypePropagator::generate_LoadQmlContextPropertyLookup(int index)
setAccumulator(m_typeResolver->scopedType(m_function->qmlScope, name, index));
+ const auto qmlScope = m_function->qmlScope.containedType();
if (!m_state.accumulatorOut().isValid() && m_typeResolver->isPrefix(name)) {
- const QQmlJSRegisterContent inType = m_typeResolver->globalType(m_function->qmlScope);
+ const QQmlJSRegisterContent inType = m_typeResolver->globalType(qmlScope);
setAccumulator(QQmlJSRegisterContent::create(
- m_typeResolver->voidType(), nameIndex, QQmlJSRegisterContent::ScopeModulePrefix,
- m_typeResolver->containedType(inType)));
+ nameIndex, m_typeResolver->voidType(), QQmlJSRegisterContent::ScopeModulePrefix,
+ inType.containedType()));
return;
}
- checkDeprecated(m_function->qmlScope, name, false);
+ checkDeprecated(qmlScope, name, false);
if (!m_state.accumulatorOut().isValid()) {
setError(u"Cannot access value for name "_s + name);
@@ -585,18 +588,9 @@ void QQmlJSTypePropagator::generate_LoadQmlContextPropertyLookup(int index)
return;
}
- const QQmlJSScope::ConstPtr outStored
- = m_typeResolver->genericType(m_state.accumulatorOut().storedType());
-
- if (outStored.isNull()) {
- // It should really be valid.
- // We get the generic type from aotContext->loadQmlContextPropertyIdLookup().
- setError(u"Cannot determine generic type for "_s + name);
- return;
- }
-
- if (m_state.accumulatorOut().variant() == QQmlJSRegisterContent::ObjectById
- && !outStored->isReferenceType()) {
+ const QQmlJSRegisterContent accumulatorOut = m_state.accumulatorOut();
+ if (accumulatorOut.variant() == QQmlJSRegisterContent::ObjectById
+ && !m_typeResolver->genericType(accumulatorOut.containedType())->isReferenceType()) {
setError(u"Cannot retrieve a non-object type by ID: "_s + name);
return;
}
@@ -610,10 +604,11 @@ void QQmlJSTypePropagator::generate_LoadQmlContextPropertyLookup(int index)
void QQmlJSTypePropagator::generate_StoreNameCommon_SAcheck(const QQmlJSRegisterContent &in, const QString &name)
{
+ const auto qmlScope = m_function->qmlScope.containedType();
QQmlSA::PassManagerPrivate::get(m_passManager)->analyzeWrite(
- QQmlJSScope::createQQmlSAElement(m_function->qmlScope), name,
- QQmlJSScope::createQQmlSAElement(m_typeResolver->containedType(in)),
- QQmlJSScope::createQQmlSAElement(m_function->qmlScope),
+ QQmlJSScope::createQQmlSAElement(qmlScope), name,
+ QQmlJSScope::createQQmlSAElement(in.containedType()),
+ QQmlJSScope::createQQmlSAElement(qmlScope),
QQmlSA::SourceLocationPrivate::createQQmlSASourceLocation(
getCurrentBindingSourceLocation()));
}
@@ -671,7 +666,7 @@ void QQmlJSTypePropagator::generate_StoreNameCommon(int nameIndex)
if (m_typeResolver->canHoldUndefined(in) && !m_typeResolver->canHoldUndefined(type)) {
- if (m_typeResolver->registerIsStoredIn(in, m_typeResolver->voidType()))
+ if (m_typeResolver->registerContains(in, m_typeResolver->voidType()))
addReadAccumulator(m_typeResolver->globalType(m_typeResolver->varType()));
else
addReadAccumulator(in);
@@ -740,7 +735,7 @@ void QQmlJSTypePropagator::generate_LoadElement(int base)
addReadRegister(base, baseRegister);
if (m_typeResolver->isNumeric(m_state.accumulatorIn())) {
- const auto contained = m_typeResolver->containedType(m_state.accumulatorIn());
+ const auto contained = m_state.accumulatorIn().containedType();
if (m_typeResolver->isSignedInteger(contained))
addReadAccumulator(m_typeResolver->globalType(m_typeResolver->sizeType()));
else if (m_typeResolver->isUnsignedInteger(contained))
@@ -779,7 +774,7 @@ void QQmlJSTypePropagator::generate_StoreElement(int base, int index)
return;
}
- const auto contained = m_typeResolver->containedType(indexRegister);
+ const auto contained = indexRegister.containedType();
if (m_typeResolver->isSignedInteger(contained))
addReadRegister(index, m_typeResolver->globalType(m_typeResolver->int32Type()));
else if (m_typeResolver->isUnsignedInteger(contained))
@@ -805,10 +800,11 @@ void QQmlJSTypePropagator::propagatePropertyLookup_SAcheck(const QString &proper
QQmlSA::PassManagerPrivate::get(m_passManager)->analyzeRead(
QQmlJSScope::createQQmlSAElement(
- m_typeResolver->containedType(m_state.accumulatorIn())),
+ m_state.accumulatorIn().containedType()),
propertyName,
- QQmlJSScope::createQQmlSAElement(isAttached ? m_attachedContext
- : m_function->qmlScope),
+ QQmlJSScope::createQQmlSAElement(isAttached
+ ? m_attachedContext
+ : m_function->qmlScope.containedType()),
QQmlSA::SourceLocationPrivate::createQQmlSASourceLocation(
getCurrentBindingSourceLocation()));
}
@@ -828,10 +824,10 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName,
Q_ASSERT(m_state.accumulatorIn().isValid());
addReadAccumulator(m_state.accumulatorIn());
setAccumulator(QQmlJSRegisterContent::create(
- m_state.accumulatorIn().storedType(),
m_jsUnitGenerator->getStringId(propertyName),
+ m_state.accumulatorIn().containedType(),
QQmlJSRegisterContent::ObjectModulePrefix,
- m_typeResolver->containedType(m_state.accumulatorIn())));
+ m_state.accumulatorIn().containedType()));
return;
}
if (m_state.accumulatorIn().isImportNamespace())
@@ -866,14 +862,14 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName,
setError(u"Cannot load property %1 from %2."_s
.arg(propertyName, m_state.accumulatorIn().descriptiveName()));
- const QString typeName = m_typeResolver->containedTypeName(m_state.accumulatorIn(), true);
+ const QString typeName = m_state.accumulatorIn().containedTypeName();
if (typeName == u"QVariant")
return;
if (m_state.accumulatorIn().isList() && propertyName == u"length")
return;
- auto baseType = m_typeResolver->containedType(m_state.accumulatorIn());
+ auto baseType = m_state.accumulatorIn().containedType();
// Warn separately when a property is only not found because of a missing type
if (propertyResolution(baseType, propertyName) != PropertyMissing)
@@ -924,7 +920,7 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName,
prop.setType(m_typeResolver->realType());
setAccumulator(
QQmlJSRegisterContent::create(
- m_typeResolver->realType(), prop, m_state.accumulatorIn().resultLookupIndex(), lookupIndex,
+ prop, m_state.accumulatorIn().resultLookupIndex(), lookupIndex,
QQmlJSRegisterContent::GenericObjectProperty, mathObject)
);
@@ -949,7 +945,7 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName,
propagatePropertyLookup_SAcheck(propertyName);
if (m_state.accumulatorOut().variant() == QQmlJSRegisterContent::ObjectAttached)
- m_attachedContext = m_typeResolver->containedType(m_state.accumulatorIn());
+ m_attachedContext = m_state.accumulatorIn().containedType();
switch (m_state.accumulatorOut().variant()) {
case QQmlJSRegisterContent::ObjectEnum:
@@ -995,12 +991,13 @@ void QQmlJSTypePropagator::generate_StoreProperty_SAcheck(const QString property
const bool isAttached = callBase.variant() == QQmlJSRegisterContent::ObjectAttached;
QQmlSA::PassManagerPrivate::get(m_passManager)->analyzeWrite(
- QQmlJSScope::createQQmlSAElement(m_typeResolver->containedType(callBase)),
+ QQmlJSScope::createQQmlSAElement(callBase.containedType()),
propertyName,
QQmlJSScope::createQQmlSAElement(
- m_typeResolver->containedType(m_state.accumulatorIn())),
- QQmlJSScope::createQQmlSAElement(isAttached ? m_attachedContext
- : m_function->qmlScope),
+ m_state.accumulatorIn().containedType()),
+ QQmlJSScope::createQQmlSAElement(isAttached
+ ? m_attachedContext
+ : m_function->qmlScope.containedType()),
QQmlSA::SourceLocationPrivate::createQQmlSASourceLocation(
getCurrentBindingSourceLocation()));
}
@@ -1017,13 +1014,13 @@ void QQmlJSTypePropagator::generate_StoreProperty(int nameIndex, int base)
return;
}
- if (property.storedType().isNull()) {
+ if (property.containedType().isNull()) {
setError(u"Cannot determine type for property %1 of type %2"_s.arg(
propertyName, callBase.descriptiveName()));
return;
}
- if (!property.isWritable() && !property.storedType()->isListProperty()) {
+ if (!property.isWritable() && !property.containedType()->isListProperty()) {
setError(u"Can't assign to read-only property %1"_s.arg(propertyName));
m_logger->log(u"Cannot assign to read-only property %1"_s.arg(propertyName),
@@ -1052,7 +1049,7 @@ void QQmlJSTypePropagator::generate_StoreProperty(int nameIndex, int base)
const QQmlJSScope::ConstPtr varType = m_typeResolver->varType();
const QQmlJSRegisterContent readType = m_typeResolver->canHoldUndefined(m_state.accumulatorIn())
- ? property.storedIn(varType).castTo(varType)
+ ? property.castTo(varType)
: std::move(property);
addReadAccumulator(readType);
addReadRegister(base, callBase);
@@ -1147,7 +1144,7 @@ void QQmlJSTypePropagator::generate_CallProperty_SCconsole(int base, int argc, i
if (argc > 0) {
const QQmlJSRegisterContent firstContent = m_state.registers[argv].content;
- const QQmlJSScope::ConstPtr firstArg = m_typeResolver->containedType(firstContent);
+ const QQmlJSScope::ConstPtr firstArg = firstContent.containedType();
switch (firstArg->accessSemantics()) {
case QQmlJSScope::AccessSemantics::Reference:
// We cannot know whether this will be a logging category at run time.
@@ -1166,7 +1163,7 @@ void QQmlJSTypePropagator::generate_CallProperty_SCconsole(int base, int argc, i
for (int i = 1; i < argc; ++i) {
const QQmlJSRegisterContent argContent = m_state.registers[argv + i].content;
- const QQmlJSScope::ConstPtr arg = m_typeResolver->containedType(argContent);
+ const QQmlJSScope::ConstPtr arg = argContent.containedType();
addReadRegister(
argv + i,
arg->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence
@@ -1185,7 +1182,7 @@ void QQmlJSTypePropagator::generate_callProperty_SAcheck(const QString propertyN
// TODO: Should there be an analyzeCall() in the future? (w. corresponding onCall in Pass)
QQmlSA::PassManagerPrivate::get(m_passManager)->analyzeRead(
QQmlJSScope::createQQmlSAElement(baseType), propertyName,
- QQmlJSScope::createQQmlSAElement(m_function->qmlScope),
+ QQmlJSScope::createQQmlSAElement(m_function->qmlScope.containedType()),
QQmlSA::SourceLocationPrivate::createQQmlSASourceLocation(
getCurrentBindingSourceLocation()));
}
@@ -1206,7 +1203,7 @@ void QQmlJSTypePropagator::generate_CallProperty(int nameIndex, int base, int ar
return;
}
- const auto baseType = m_typeResolver->containedType(callBase);
+ const auto baseType = callBase.containedType();
const auto member = m_typeResolver->memberType(callBase, propertyName);
if (!member.isMethod()) {
@@ -1241,7 +1238,7 @@ void QQmlJSTypePropagator::generate_CallProperty(int nameIndex, int base, int ar
}
m_logger->log(u"Member \"%1\" not found on type \"%2\""_s.arg(
- propertyName, m_typeResolver->containedTypeName(callBase, true)),
+ propertyName, callBase.containedTypeName()),
qmlMissingProperty, getCurrentSourceLocation(), true, true, fixSuggestion);
return;
}
@@ -1320,7 +1317,7 @@ QQmlJSMetaMethod QQmlJSTypePropagator::bestMatchForCall(const QList<QQmlJSMetaMe
// We can try to call a method that expects a derived type.
if (argumentType->isReferenceType()
&& m_typeResolver->inherits(
- argumentType->baseType(), m_typeResolver->containedType(content))) {
+ argumentType->baseType(), content.containedType())) {
continue;
}
@@ -1358,7 +1355,7 @@ void QQmlJSTypePropagator::setRegister(int index, const QQmlJSRegisterContent &c
auto it = m_prevStateAnnotations.find(currentInstructionOffset());
if (it != m_prevStateAnnotations.end()) {
const QQmlJSRegisterContent &lastTry = it->second.changedRegister;
- if (m_typeResolver->registerContains(lastTry, m_typeResolver->containedType(content))) {
+ if (m_typeResolver->registerContains(lastTry, content.containedType())) {
m_state.setRegister(index, lastTry);
return;
}
@@ -1444,7 +1441,7 @@ void QQmlJSTypePropagator::propagateCall(
? m_typeResolver->jsValueType()
: QQmlJSScope::ConstPtr(match.returnType());
setAccumulator(m_typeResolver->returnType(
- returnType ? QQmlJSScope::ConstPtr(returnType) : m_typeResolver->voidType(),
+ returnType,
match.isJavaScriptFunction()
? QQmlJSRegisterContent::JavaScriptReturnValue
: QQmlJSRegisterContent::MethodReturnValue,
@@ -1583,8 +1580,7 @@ void QQmlJSTypePropagator::propagateStringArgCall(int argv)
m_typeResolver->stringType()));
Q_ASSERT(m_state.accumulatorOut().isValid());
- const QQmlJSScope::ConstPtr input = m_typeResolver->containedType(
- m_state.registers[argv].content);
+ const QQmlJSScope::ConstPtr input = m_state.registers[argv].content.containedType();
if (m_typeResolver->equals(input, m_typeResolver->uint32Type())) {
addReadRegister(argv, m_typeResolver->globalType(m_typeResolver->realType()));
@@ -1621,7 +1617,7 @@ bool QQmlJSTypePropagator::propagateArrayMethod(
const auto intType = m_typeResolver->globalType(m_typeResolver->int32Type());
const auto stringType = m_typeResolver->globalType(m_typeResolver->stringType());
- const auto baseContained = m_typeResolver->containedType(baseType);
+ const auto baseContained = baseType.containedType();
const auto valueContained = baseContained->valueType();
const auto valueType = m_typeResolver->globalType(valueContained);
@@ -1728,7 +1724,7 @@ bool QQmlJSTypePropagator::propagateArrayMethod(
for (int i = 0; i < argc; ++i)
addReadRegister(argv + i, intType);
- setReturnType(baseType.storedType()->isListProperty()
+ setReturnType(baseType.containedType()->isListProperty()
? m_typeResolver->qObjectListType()
: baseContained);
return true;
@@ -1827,7 +1823,7 @@ void QQmlJSTypePropagator::generate_CallQmlContextPropertyLookup(int index, int
{
const QString name = m_jsUnitGenerator->lookupName(index);
propagateScopeLookupCall(name, argc, argv);
- checkDeprecated(m_function->qmlScope, name, true);
+ checkDeprecated(m_function->qmlScope.containedType(), name, true);
}
void QQmlJSTypePropagator::generate_CallWithSpread(int func, int thisObject, int argc, int argv)
@@ -2246,7 +2242,7 @@ void QQmlJSTypePropagator::recordEqualsNullType()
{
// TODO: We can specialize this further, for QVariant, QJSValue, int, bool, whatever.
if (m_typeResolver->registerContains(m_state.accumulatorIn(), m_typeResolver->nullType())
- || m_typeResolver->containedType(m_state.accumulatorIn())->isReferenceType()) {
+ || m_state.accumulatorIn().containedType()->isReferenceType()) {
addReadAccumulator(m_state.accumulatorIn());
} else {
addReadAccumulator(m_typeResolver->globalType(m_typeResolver->jsPrimitiveType()));
@@ -2255,7 +2251,7 @@ void QQmlJSTypePropagator::recordEqualsNullType()
void QQmlJSTypePropagator::recordEqualsIntType()
{
// We have specializations for numeric types and bool.
- const QQmlJSScope::ConstPtr in = m_typeResolver->containedType(m_state.accumulatorIn());
+ const QQmlJSScope::ConstPtr in = m_state.accumulatorIn().containedType();
if (m_typeResolver->registerContains(m_state.accumulatorIn(), m_typeResolver->boolType())
|| m_typeResolver->isNumeric(m_state.accumulatorIn())) {
addReadAccumulator(m_state.accumulatorIn());
@@ -2275,7 +2271,7 @@ void QQmlJSTypePropagator::recordEqualsType(int lhs)
// If the types are primitive, we compare directly ...
if (m_typeResolver->isPrimitive(accumulatorIn) || accumulatorIn.isEnumeration()) {
if (m_typeResolver->registerContains(
- accumulatorIn, m_typeResolver->containedType(lhsRegister))
+ accumulatorIn, lhsRegister.containedType())
|| (isNumericOrEnum(accumulatorIn) && isNumericOrEnum(lhsRegister))
|| m_typeResolver->isPrimitive(lhsRegister)) {
addReadRegister(lhs, lhsRegister);
@@ -2286,11 +2282,11 @@ void QQmlJSTypePropagator::recordEqualsType(int lhs)
const auto containedAccumulatorIn = m_typeResolver->isOptionalType(accumulatorIn)
? m_typeResolver->extractNonVoidFromOptionalType(accumulatorIn)
- : m_typeResolver->containedType(accumulatorIn);
+ : accumulatorIn.containedType();
const auto containedLhs = m_typeResolver->isOptionalType(lhsRegister)
? m_typeResolver->extractNonVoidFromOptionalType(lhsRegister)
- : m_typeResolver->containedType(lhsRegister);
+ : lhsRegister.containedType();
// We don't modify types if the types are comparable with QObject, QUrl or var types
if (canStrictlyCompareWithVar(m_typeResolver, containedLhs, containedAccumulatorIn)
@@ -2421,7 +2417,7 @@ void QQmlJSTypePropagator::generate_CmpInstanceOf(int lhs)
void QQmlJSTypePropagator::generate_As(int lhs)
{
const QQmlJSRegisterContent input = checkedInputRegister(lhs);
- const QQmlJSScope::ConstPtr inContained = m_typeResolver->containedType(input);
+ const QQmlJSScope::ConstPtr inContained = input.containedType();
QQmlJSScope::ConstPtr outContained;
@@ -2435,7 +2431,7 @@ void QQmlJSTypePropagator::generate_As(int lhs)
addReadAccumulator(m_typeResolver->globalType(m_typeResolver->metaObjectType()));
break;
default:
- outContained = m_typeResolver->containedType(m_state.accumulatorIn());
+ outContained = m_state.accumulatorIn().containedType();
break;
}
@@ -2794,12 +2790,6 @@ QQmlJSRegisterContent QQmlJSTypePropagator::propagateBinaryOperation(QSOperator:
op, lhsRegister, m_state.accumulatorIn());
setAccumulator(type);
-
- // If we're dealing with QJSPrimitiveType, do not force premature conversion of the arguemnts
- // to the target type. Such an operation can lose information.
- if (type.storedType() == m_typeResolver->jsPrimitiveType())
- return m_typeResolver->globalType(m_typeResolver->jsPrimitiveType());
-
return type;
}
diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp
index 93f9c7f7f4..245aedec55 100644
--- a/src/qmlcompiler/qqmljstyperesolver.cpp
+++ b/src/qmlcompiler/qqmljstyperesolver.cpp
@@ -17,7 +17,7 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-Q_LOGGING_CATEGORY(lcTypeResolver, "qt.qml.compiler.typeresolver", QtInfoMsg);
+Q_STATIC_LOGGING_CATEGORY(lcTypeResolver, "qt.qml.compiler.typeresolver", QtInfoMsg);
static inline void assertExtension(const QQmlJSScope::ConstPtr &type, QLatin1String extension)
{
@@ -270,8 +270,8 @@ QQmlJSTypeResolver::typeForBinaryOperation(QSOperator::Op oper, const QQmlJSRegi
case QSOperator::Op::URShift:
return builtinType(uint32Type());
case QSOperator::Op::Add: {
- const auto leftContents = containedType(left);
- const auto rightContents = containedType(right);
+ const auto leftContents = left.containedType();
+ const auto rightContents = right.containedType();
if (equals(leftContents, stringType()) || equals(rightContents, stringType()))
return builtinType(stringType());
@@ -286,7 +286,7 @@ QQmlJSTypeResolver::typeForBinaryOperation(QSOperator::Op oper, const QQmlJSRegi
case QSOperator::Op::Sub:
case QSOperator::Op::Mul:
case QSOperator::Op::Exp: {
- const QQmlJSScope::ConstPtr result = merge(containedType(left), containedType(right));
+ const QQmlJSScope::ConstPtr result = merge(left.containedType(), right.containedType());
return builtinType(equals(result, boolType()) ? int32Type() : realType());
}
case QSOperator::Op::Div:
@@ -314,7 +314,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::typeForArithmeticUnaryOperation(
return operand;
Q_FALLTHROUGH();
default:
- if (equals(containedType(operand), boolType()))
+ if (equals(operand.containedType(), boolType()))
return builtinType(int32Type());
break;
}
@@ -324,17 +324,17 @@ QQmlJSRegisterContent QQmlJSTypeResolver::typeForArithmeticUnaryOperation(
bool QQmlJSTypeResolver::isPrimitive(const QQmlJSRegisterContent &type) const
{
- return isPrimitive(containedType(type));
+ return isPrimitive(type.containedType());
}
bool QQmlJSTypeResolver::isNumeric(const QQmlJSRegisterContent &type) const
{
- return isNumeric(containedType(type));
+ return isNumeric(type.containedType());
}
bool QQmlJSTypeResolver::isIntegral(const QQmlJSRegisterContent &type) const
{
- return isIntegral(containedType(type));
+ return isIntegral(type.containedType());
}
bool QQmlJSTypeResolver::isIntegral(const QQmlJSScope::ConstPtr &type) const
@@ -386,33 +386,6 @@ bool QQmlJSTypeResolver::isNativeArrayIndex(const QQmlJSScope::ConstPtr &type) c
|| equals(type, m_int32Type));
}
-QQmlJSScope::ConstPtr
-QQmlJSTypeResolver::containedType(const QQmlJSRegisterContent &container) const
-{
- if (container.isType())
- return container.type();
- if (container.isProperty())
- return container.property().type();
- if (container.isEnumeration())
- return container.enumeration().type();
- if (container.isMethod())
- return container.storedType(); // Methods can only be stored in QJSValue.
- if (container.isImportNamespace()) {
- switch (container.variant()) {
- case QQmlJSRegisterContent::ScopeModulePrefix:
- return container.storedType(); // We don't store scope module prefixes
- case QQmlJSRegisterContent::ObjectModulePrefix:
- return container.scopeType(); // We need to pass the original object through.
- default:
- Q_UNREACHABLE();
- }
- }
- if (container.isConversion())
- return container.conversionResult();
-
- Q_UNREACHABLE_RETURN({});
-}
-
QQmlJSScope::ConstPtr QQmlJSTypeResolver::trackedType(const QQmlJSScope::ConstPtr &type) const
{
if (m_cloneMode == QQmlJSTypeResolver::DoNotCloneTypes)
@@ -433,35 +406,35 @@ QQmlJSRegisterContent QQmlJSTypeResolver::transformed(
{
if (origin.isType()) {
return QQmlJSRegisterContent::create(
- (this->*op)(origin.storedType()), (this->*op)(origin.type()),
- origin.resultLookupIndex(), origin.variant(), (this->*op)(origin.scopeType()));
+ (this->*op)(origin.type()), origin.resultLookupIndex(), origin.variant(),
+ (this->*op)(origin.scopeType()));
}
if (origin.isProperty()) {
QQmlJSMetaProperty prop = origin.property();
prop.setType((this->*op)(prop.type()));
return QQmlJSRegisterContent::create(
- (this->*op)(origin.storedType()), prop, origin.baseLookupIndex(),
- origin.resultLookupIndex(), origin.variant(), (this->*op)(origin.scopeType()));
+ prop, origin.baseLookupIndex(), origin.resultLookupIndex(), origin.variant(),
+ (this->*op)(origin.scopeType()));
}
if (origin.isEnumeration()) {
QQmlJSMetaEnum enumeration = origin.enumeration();
enumeration.setType((this->*op)(enumeration.type()));
return QQmlJSRegisterContent::create(
- (this->*op)(origin.storedType()), enumeration, origin.enumMember(),
- origin.variant(), (this->*op)(origin.scopeType()));
+ enumeration, origin.enumMember(), origin.variant(),
+ (this->*op)(origin.scopeType()));
}
if (origin.isMethod()) {
return QQmlJSRegisterContent::create(
- (this->*op)(origin.storedType()), origin.method(), origin.variant(),
+ origin.method(), (this->*op)(origin.methodType()), origin.variant(),
(this->*op)(origin.scopeType()));
}
if (origin.isImportNamespace()) {
return QQmlJSRegisterContent::create(
- (this->*op)(origin.storedType()), origin.importNamespace(),
+ origin.importNamespace(), (this->*op)(origin.importNamespaceType()),
origin.variant(), (this->*op)(origin.scopeType()));
}
@@ -480,7 +453,6 @@ QQmlJSRegisterContent QQmlJSTypeResolver::transformed(
}
return QQmlJSRegisterContent::create(
- (this->*op)(origin.storedType()),
transformedOrigins,
(this->*op)(origin.conversionResult()),
(this->*op)(origin.conversionResultScope()),
@@ -490,6 +462,28 @@ QQmlJSRegisterContent QQmlJSTypeResolver::transformed(
Q_UNREACHABLE_RETURN({});
}
+QQmlJSScope::ConstPtr QQmlJSTypeResolver::containedTypeForName(const QString &name) const
+{
+ QQmlJSScope::ConstPtr type = typeForName(name);
+
+ if (!type || type->isSingleton() || type->isScript())
+ return type;
+
+ switch (type->accessSemantics()) {
+ case QQmlJSScope::AccessSemantics::Reference:
+ if (const auto attached = type->attachedType())
+ return genericType(attached) ? attached : QQmlJSScope::ConstPtr();
+ return metaObjectType();
+ case QQmlJSScope::AccessSemantics::None:
+ return metaObjectType();
+ case QQmlJSScope::AccessSemantics::Sequence:
+ case QQmlJSScope::AccessSemantics::Value:
+ return canAddressValueTypes() ? metaObjectType() : QQmlJSScope::ConstPtr();
+ }
+
+ Q_UNREACHABLE_RETURN(QQmlJSScope::ConstPtr());
+}
+
QQmlJSRegisterContent QQmlJSTypeResolver::registerContentForName(
const QString &name, const QQmlJSScope::ConstPtr &scopeType,
bool hasObjectModulePrefix) const
@@ -500,13 +494,13 @@ QQmlJSRegisterContent QQmlJSTypeResolver::registerContentForName(
if (type->isSingleton()) {
return QQmlJSRegisterContent::create(
- storedType(type), type, QQmlJSRegisterContent::InvalidLookupIndex,
+ type, QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::Singleton, scopeType);
}
if (type->isScript()) {
return QQmlJSRegisterContent::create(
- storedType(type), type, QQmlJSRegisterContent::InvalidLookupIndex,
+ type, QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::Script, scopeType);
}
@@ -526,7 +520,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::registerContentForName(
// mode, we will figure this out using the scope type and access any enums of the
// plain type directly. In indirect mode, we can use enum lookups.
return QQmlJSRegisterContent::create(
- storedType(attached), attached, QQmlJSRegisterContent::InvalidLookupIndex,
+ attached, QQmlJSRegisterContent::InvalidLookupIndex,
hasObjectModulePrefix
? QQmlJSRegisterContent::ObjectAttached
: QQmlJSRegisterContent::ScopeAttached, type);
@@ -541,13 +535,13 @@ QQmlJSRegisterContent QQmlJSTypeResolver::registerContentForName(
// Store it as QMetaObject.
// This only works with namespaces and object types.
return QQmlJSRegisterContent::create(
- metaObjectType(), metaObjectType(), QQmlJSRegisterContent::InvalidLookupIndex,
+ metaObjectType(), QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::MetaType, type);
case QQmlJSScope::AccessSemantics::Sequence:
case QQmlJSScope::AccessSemantics::Value:
if (canAddressValueTypes()) {
return QQmlJSRegisterContent::create(
- metaObjectType(), metaObjectType(), QQmlJSRegisterContent::InvalidLookupIndex,
+ metaObjectType(), QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::MetaType, type);
}
// Else this is not actually a type reference. You cannot get the metaobject
@@ -571,14 +565,14 @@ QQmlJSRegisterContent QQmlJSTypeResolver::tracked(const QQmlJSRegisterContent &t
QQmlJSScope::ConstPtr QQmlJSTypeResolver::trackedContainedType(
const QQmlJSRegisterContent &container) const
{
- const QQmlJSScope::ConstPtr type = containedType(container);
+ const QQmlJSScope::ConstPtr type = container.containedType();
return m_trackedTypes->contains(type) ? type : QQmlJSScope::ConstPtr();
}
QQmlJSScope::ConstPtr QQmlJSTypeResolver::originalContainedType(
const QQmlJSRegisterContent &container) const
{
- return originalType(containedType(container));
+ return originalType(container.containedType());
}
bool QQmlJSTypeResolver::adjustTrackedType(
@@ -655,30 +649,6 @@ void QQmlJSTypeResolver::generalizeType(const QQmlJSScope::ConstPtr &type) const
it->original = genericType(it->original);
}
-QString QQmlJSTypeResolver::containedTypeName(const QQmlJSRegisterContent &container,
- bool useFancyName) const
-{
- QQmlJSScope::ConstPtr type;
-
- // Use the type proper instead of the attached type
- switch (container.variant()) {
- case QQmlJSRegisterContent::ScopeAttached:
- case QQmlJSRegisterContent::MetaType:
- type = container.scopeType();
- break;
- default:
- type = containedType(container);
- break;
- }
-
- QString typeName = type->internalName().isEmpty() ? type->baseTypeName() : type->internalName();
-
- if (useFancyName)
- return QQmlJSScope::prettyName(typeName);
-
- return typeName;
-}
-
bool QQmlJSTypeResolver::canConvertFromTo(const QQmlJSScope::ConstPtr &from,
const QQmlJSScope::ConstPtr &to) const
{
@@ -711,7 +681,7 @@ bool QQmlJSTypeResolver::canConvertFromTo(const QQmlJSScope::ConstPtr &from,
bool QQmlJSTypeResolver::canConvertFromTo(const QQmlJSRegisterContent &from,
const QQmlJSRegisterContent &to) const
{
- return canConvertFromTo(containedType(from), containedType(to));
+ return canConvertFromTo(from.containedType(), to.containedType());
}
static QQmlJSRegisterContent::ContentVariant mergeVariants(QQmlJSRegisterContent::ContentVariant a,
@@ -733,7 +703,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::merge(const QQmlJSRegisterContent &a,
origins.append(a.conversionOrigins());
aResultScope = a.conversionResultScope();
} else {
- origins.append(containedType(a));
+ origins.append(a.containedType());
aResultScope = a.scopeType();
}
@@ -742,7 +712,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::merge(const QQmlJSRegisterContent &a,
origins.append(b.conversionOrigins());
bResultScope = b.conversionResultScope();
} else {
- origins.append(containedType(b));
+ origins.append(b.containedType());
bResultScope = b.scopeType();
}
@@ -751,9 +721,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::merge(const QQmlJSRegisterContent &a,
origins.erase(erase, origins.end());
return QQmlJSRegisterContent::create(
- merge(a.storedType(), b.storedType()),
origins,
- merge(containedType(a), containedType(b)),
+ merge(a.containedType(), b.containedType()),
merge(aResultScope, bResultScope),
mergeVariants(a.variant(), b.variant()),
merge(a.scopeType(), b.scopeType()));
@@ -871,11 +840,11 @@ bool QQmlJSTypeResolver::canHoldUndefined(const QQmlJSRegisterContent &content)
|| equals(type, m_jsValueType) || equals(type, m_jsPrimitiveType);
};
- if (!canBeUndefined(content.storedType()))
+ if (!canBeUndefined(content.containedType()))
return false;
if (!content.isConversion())
- return canBeUndefined(containedType(content));
+ return true;
const auto origins = content.conversionOrigins();
for (const auto &origin : origins) {
@@ -943,14 +912,18 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(
}
}
+ // Reference types that are not QObject or QQmlComponent are likely JavaScript objects.
+ // We don't want to deal with those, but m_jsValueType is the best generic option.
+ if (type->filePath().isEmpty())
+ return m_jsValueType;
+
m_logger->log(u"Object type %1 is not derived from QObject or QQmlComponent. "
"You may need to fully qualify all names in C++ so that moc can see them. "
"You may also need to add qt_extract_metatypes(<target containing %2>)."_s
.arg(type->internalName(), unresolvedBaseTypeName),
qmlCompiler, type->sourceLocation());
- // Reference types that are not QObject or QQmlComponent are likely JavaScript objects.
- // We don't want to deal with those, but m_jsValueType is the best generic option.
+ // If it does have a filePath, it's some C++ type which we haven't fully resolved.
return m_jsValueType;
}
@@ -960,8 +933,20 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(
if (type->scopeType() == QQmlSA::ScopeType::EnumScope)
return type->baseType();
- if (isPrimitive(type))
- return type;
+ if (isPrimitive(type)) {
+ // If the filePath is set, the type is storable and we can just return it.
+ if (!type->filePath().isEmpty())
+ return type;
+
+ // If the type is JavaScript's 'number' type, it's not directly storable, but still
+ // primitive. We use C++ 'double' then.
+ if (isNumeric(type))
+ return m_realType;
+
+ // Otherwise we use QJSPrimitiveValue.
+ // TODO: JavaScript's 'string' and 'boolean' could be special-cased here.
+ return m_jsPrimitiveType;
+ }
for (const QQmlJSScope::ConstPtr &builtin : {
m_realType, m_floatType, m_int8Type, m_uint8Type, m_int16Type, m_uint16Type,
@@ -981,13 +966,13 @@ QQmlJSRegisterContent QQmlJSTypeResolver::builtinType(const QQmlJSScope::ConstPt
{
Q_ASSERT(storedType(type) == type);
return QQmlJSRegisterContent::create(
- type, type, QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::Builtin);
+ type, QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::Builtin);
}
QQmlJSRegisterContent QQmlJSTypeResolver::globalType(const QQmlJSScope::ConstPtr &type) const
{
return QQmlJSRegisterContent::create(
- storedType(type), type, QQmlJSRegisterContent::InvalidLookupIndex,
+ type, QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::Unknown);
}
@@ -1024,76 +1009,168 @@ static bool isRevisionAllowed(int memberRevision, const QQmlJSScope::ConstPtr &s
return typeRevision.isValid() && typeRevision >= revision;
}
-QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSScope::ConstPtr &scope,
- const QString &name, int lookupIndex,
- QQmlJSScopesByIdOptions options) const
+QQmlJSScope::ConstPtr QQmlJSTypeResolver::resolveParentProperty(
+ const QString &name, const QQmlJSScope::ConstPtr &base,
+ const QQmlJSScope::ConstPtr &propType) const
{
- const auto isAssignedToDefaultProperty = [this](const QQmlJSScope::ConstPtr &parent,
- const QQmlJSScope::ConstPtr &child) {
- const QString defaultPropertyName = parent->defaultPropertyName();
- if (defaultPropertyName.isEmpty()) // no reason to search for bindings
- return false;
+ if (m_parentMode != UseDocumentParent || name != base->parentPropertyName())
+ return propType;
+
+ const QQmlJSScope::ConstPtr baseParent = base->parentScope();
+ if (!baseParent || !baseParent->inherits(propType))
+ return propType;
+
+ const QString defaultPropertyName = baseParent->defaultPropertyName();
+ if (defaultPropertyName.isEmpty()) // no reason to search for bindings
+ return propType;
+
+ const QList<QQmlJSMetaPropertyBinding> defaultPropBindings
+ = baseParent->propertyBindings(defaultPropertyName);
+ for (const QQmlJSMetaPropertyBinding &binding : defaultPropBindings) {
+ if (binding.bindingType() == QQmlSA::BindingType::Object
+ && equals(binding.objectType(), base)) {
+ return baseParent;
+ }
+ }
+
+ return propType;
+}
+
+/*!
+ * \internal
+ *
+ * Retrieves the type of whatever \a name signifies in the given \a scope.
+ * \a name can be an ID, a property of the scope, a singleton, an attachment,
+ * a plain type reference or a JavaScript global.
+ *
+ * TODO: The lookup is actually wrong. We cannot really retrieve JavaScript
+ * globals here because any runtime-inserted context property would
+ * override them. We still do because we don't have a better solution for
+ * identifying e.g. the console object, yet.
+ *
+ * \a options tells us whether to consider components as bound. If components
+ * are bound we can retrieve objects identified by ID in outer contexts.
+ *
+ * TODO: This is also wrong because we should alternate scopes and contexts when
+ * traveling the scope/context hierarchy. Currently we have IDs from any
+ * context override all scope properties if components are considered
+ * bound. This is mostly because we don't care about outer scopes at all;
+ * so we cannot determine with certainty whether an ID from a far outer
+ * context is overridden by a property of a near outer scope. To
+ * complicate this further, user context properties can also be inserted
+ * in outer contexts at run time, shadowing names in further removed outer
+ * scopes and contexts. What we need to do is determine where exactly what
+ * kind of property can show up and defend against that with additional
+ * pragmas.
+ *
+ * Note: It probably takes at least 3 nested bound components in one document to
+ * trigger the misbehavior.
+ */
+QQmlJSScope::ConstPtr QQmlJSTypeResolver::scopedType(
+ const QQmlJSScope::ConstPtr &scope, const QString &name,
+ QQmlJSScopesByIdOptions options) const
+{
+ if (QQmlJSScope::ConstPtr identified = m_objectsById.scope(name, scope, options))
+ return identified;
+
+ if (QQmlJSScope::ConstPtr base = QQmlJSScope::findCurrentQMLScope(scope)) {
+ QQmlJSScope::ConstPtr result;
+ if (QQmlJSUtils::searchBaseAndExtensionTypes(
+ base, [&](const QQmlJSScope::ConstPtr &found, QQmlJSScope::ExtensionKind mode) {
+ if (mode == QQmlJSScope::ExtensionNamespace) // no use for it here
+ return false;
+
+ if (found->hasOwnProperty(name)) {
+ const QQmlJSMetaProperty prop = found->ownProperty(name);
+ if (!isRevisionAllowed(prop.revision(), scope))
+ return false;
- const QList<QQmlJSMetaPropertyBinding> defaultPropBindings =
- parent->propertyBindings(defaultPropertyName);
- for (const QQmlJSMetaPropertyBinding &binding : defaultPropBindings) {
- if (binding.bindingType() == QQmlSA::BindingType::Object
- && equals(binding.objectType(), child)) {
+ result = resolveParentProperty(name, base, prop.type());
return true;
}
+
+ if (found->hasOwnMethod(name)) {
+ const auto methods = found->ownMethods(name);
+ for (const auto &method : methods) {
+ if (isRevisionAllowed(method.revision(), scope)) {
+ result = jsValueType();
+ return true;
+ }
+ }
+ }
+
+ return false;
+ })) {
+ return result;
}
- return false;
- };
+ }
+
+ if (QQmlJSScope::ConstPtr result = containedTypeForName(name))
+ return result;
+
+ if (m_jsGlobalObject->hasProperty(name))
+ return m_jsGlobalObject->property(name).type();
+
+ if (m_jsGlobalObject->hasMethod(name))
+ return jsValueType();
+
+ return {};
+}
- if (QQmlJSScope::ConstPtr identified = m_objectsById.scope(name, scope, options)) {
- return QQmlJSRegisterContent::create(storedType(identified), identified, lookupIndex,
- QQmlJSRegisterContent::ObjectById, scope);
+/*!
+ * \internal
+ *
+ * Same as the other scopedType method, but accepts a QQmlJSRegisterContent and
+ * also returns one. This way you not only get the type, but also the content
+ * variant and various meta info.
+ */
+QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSRegisterContent &scope,
+ const QString &name, int lookupIndex,
+ QQmlJSScopesByIdOptions options) const
+{
+ const QQmlJSScope::ConstPtr contained = scope.containedType();
+ if (QQmlJSScope::ConstPtr identified = m_objectsById.scope(name, contained, options)) {
+ return QQmlJSRegisterContent::create(
+ identified, lookupIndex, QQmlJSRegisterContent::ObjectById, contained);
}
- if (QQmlJSScope::ConstPtr base = QQmlJSScope::findCurrentQMLScope(scope)) {
+ if (QQmlJSScope::ConstPtr base = QQmlJSScope::findCurrentQMLScope(contained)) {
QQmlJSRegisterContent result;
if (QQmlJSUtils::searchBaseAndExtensionTypes(
base, [&](const QQmlJSScope::ConstPtr &found, QQmlJSScope::ExtensionKind mode) {
- if (mode == QQmlJSScope::ExtensionNamespace) // no use for it here
- return false;
- if (found->hasOwnProperty(name)) {
- QQmlJSMetaProperty prop = found->ownProperty(name);
- if (!isRevisionAllowed(prop.revision(), scope))
- return false;
- if (m_parentMode == UseDocumentParent
- && name == base->parentPropertyName()) {
- QQmlJSScope::ConstPtr baseParent = base->parentScope();
- if (baseParent && baseParent->inherits(prop.type())
- && isAssignedToDefaultProperty(baseParent, base)) {
- prop.setType(baseParent);
- }
- }
- result = QQmlJSRegisterContent::create(
- storedType(prop.type()), prop,
- QQmlJSRegisterContent::InvalidLookupIndex, lookupIndex,
- scopeContentVariant(mode, false), scope);
- return true;
- }
-
- if (found->hasOwnMethod(name)) {
- auto methods = found->ownMethods(name);
- for (auto it = methods.begin(); it != methods.end();) {
- if (!isRevisionAllowed(it->revision(), scope))
- it = methods.erase(it);
- else
- ++it;
- }
- if (methods.isEmpty())
- return false;
- result = QQmlJSRegisterContent::create(
- jsValueType(), methods, scopeContentVariant(mode, true), scope);
- return true;
- }
-
- // Unqualified enums are not allowed
-
- return false;
- })) {
+ if (mode == QQmlJSScope::ExtensionNamespace) // no use for it here
+ return false;
+
+ if (found->hasOwnProperty(name)) {
+ QQmlJSMetaProperty prop = found->ownProperty(name);
+ if (!isRevisionAllowed(prop.revision(), contained))
+ return false;
+
+ prop.setType(resolveParentProperty(name, base, prop.type()));
+ result = QQmlJSRegisterContent::create(
+ prop, QQmlJSRegisterContent::InvalidLookupIndex, lookupIndex,
+ scopeContentVariant(mode, false), contained);
+ return true;
+ }
+
+ if (found->hasOwnMethod(name)) {
+ auto methods = found->ownMethods(name);
+ for (auto it = methods.begin(); it != methods.end();) {
+ if (!isRevisionAllowed(it->revision(), contained))
+ it = methods.erase(it);
+ else
+ ++it;
+ }
+ if (methods.isEmpty())
+ return false;
+ result = QQmlJSRegisterContent::create(
+ methods, jsValueType(), scopeContentVariant(mode, true), contained);
+ return true;
+ }
+
+ // Unqualified enums are not allowed
+ return false;
+ })) {
return result;
}
}
@@ -1105,18 +1182,30 @@ QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSScope::ConstPtr
if (m_jsGlobalObject->hasProperty(name)) {
return QQmlJSRegisterContent::create(
- jsValueType(), m_jsGlobalObject->property(name),
- QQmlJSRegisterContent::InvalidLookupIndex, lookupIndex,
- QQmlJSRegisterContent::JavaScriptGlobal, m_jsGlobalObject);
+ m_jsGlobalObject->property(name), QQmlJSRegisterContent::InvalidLookupIndex,
+ lookupIndex, QQmlJSRegisterContent::JavaScriptGlobal, m_jsGlobalObject);
} else if (m_jsGlobalObject->hasMethod(name)) {
- return QQmlJSRegisterContent::create(jsValueType(), m_jsGlobalObject->methods(name),
- QQmlJSRegisterContent::JavaScriptGlobal,
- m_jsGlobalObject);
+ return QQmlJSRegisterContent::create(
+ m_jsGlobalObject->methods(name), jsValueType(),
+ QQmlJSRegisterContent::JavaScriptGlobal, m_jsGlobalObject);
}
return {};
}
+/*!
+ * \fn QQmlJSScope::ConstPtr typeForId(const QQmlJSScope::ConstPtr &scope, const QString &name, QQmlJSScopesByIdOptions options) const
+ *
+ * \internal
+ *
+ * Same as scopedType(), but assumes that the \a name is an ID and only searches
+ * the context.
+ *
+ * TODO: This is just as wrong as scopedType() in that it disregards both scope
+ * properties overriding context properties and run time context
+ * properties.
+ */
+
bool QQmlJSTypeResolver::checkEnums(const QQmlJSScope::ConstPtr &scope, const QString &name,
QQmlJSRegisterContent *result,
QQmlJSScope::ExtensionKind mode) const
@@ -1131,7 +1220,7 @@ bool QQmlJSTypeResolver::checkEnums(const QQmlJSScope::ConstPtr &scope, const QS
for (const auto &enumeration : enums) {
if ((enumeration.isScoped() || enumeration.isQml()) && enumeration.name() == name) {
*result = QQmlJSRegisterContent::create(
- storedType(enumeration.type()), enumeration, QString(),
+ enumeration, QString(),
inExtension ? QQmlJSRegisterContent::ExtensionObjectEnum
: QQmlJSRegisterContent::ObjectEnum,
scope);
@@ -1140,7 +1229,7 @@ bool QQmlJSTypeResolver::checkEnums(const QQmlJSScope::ConstPtr &scope, const QS
if (!enumeration.isScoped() && enumeration.hasKey(name)) {
*result = QQmlJSRegisterContent::create(
- storedType(enumeration.type()), enumeration, name,
+ enumeration, name,
inExtension ? QQmlJSRegisterContent::ExtensionObjectEnum
: QQmlJSRegisterContent::ObjectEnum,
scope);
@@ -1409,7 +1498,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::lengthProperty(
prop.setType(sizeType());
prop.setIsWritable(isWritable);
return QQmlJSRegisterContent::create(
- sizeType(), prop, QQmlJSRegisterContent::InvalidLookupIndex,
+ prop, QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::Builtin, scope);
}
@@ -1430,7 +1519,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
prop.setType(varType());
prop.setIsWritable(true);
return QQmlJSRegisterContent::create(
- varType(), prop, baseLookupIndex, resultLookupIndex,
+ prop, baseLookupIndex, resultLookupIndex,
QQmlJSRegisterContent::GenericObjectProperty, type);
}
@@ -1441,7 +1530,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
prop.setType(jsValueType());
prop.setIsWritable(true);
return QQmlJSRegisterContent::create(
- jsValueType(), prop, baseLookupIndex, resultLookupIndex,
+ prop, baseLookupIndex, resultLookupIndex,
QQmlJSRegisterContent::GenericObjectProperty, type);
}
@@ -1456,7 +1545,6 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
if (scope->hasOwnProperty(name)) {
const auto prop = scope->ownProperty(name);
result = QQmlJSRegisterContent::create(
- storedType(prop.type()),
prop, baseLookupIndex, resultLookupIndex,
mode == QQmlJSScope::NotExtension
? QQmlJSRegisterContent::ObjectProperty
@@ -1468,7 +1556,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
if (scope->hasOwnMethod(name)) {
const auto methods = scope->ownMethods(name);
result = QQmlJSRegisterContent::create(
- jsValueType(), methods,
+ methods, jsValueType(),
mode == QQmlJSScope::NotExtension
? QQmlJSRegisterContent::ObjectMethod
: QQmlJSRegisterContent::ExtensionObjectMethod,
@@ -1494,9 +1582,9 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
prop.setType(jsValueType());
prop.setIsWritable(!(ownIdentifier.value().isConst));
- return QQmlJSRegisterContent::create(jsValueType(), prop, baseLookupIndex,
- resultLookupIndex,
- QQmlJSRegisterContent::JavaScriptObject, scope);
+ return QQmlJSRegisterContent::create(
+ prop, baseLookupIndex, resultLookupIndex,
+ QQmlJSRegisterContent::JavaScriptObject, scope);
}
}
@@ -1514,8 +1602,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
return {};
} else {
return QQmlJSRegisterContent::create(
- storedType(attached), attached, resultLookupIndex,
- QQmlJSRegisterContent::ObjectAttached, attachedBase);
+ attached, resultLookupIndex, QQmlJSRegisterContent::ObjectAttached,
+ attachedBase);
}
}
}
@@ -1557,8 +1645,8 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
const auto enumeration = type.enumeration();
if (!type.enumMember().isEmpty() || !enumeration.hasKey(name))
return {};
- return QQmlJSRegisterContent::create(storedType(enumeration.type()), enumeration, name,
- QQmlJSRegisterContent::ObjectEnum, type.scopeType());
+ return QQmlJSRegisterContent::create(
+ enumeration, name, QQmlJSRegisterContent::ObjectEnum, type.scopeType());
}
if (type.isMethod()) {
QQmlJSMetaProperty prop;
@@ -1567,7 +1655,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(
prop.setType(jsValueType());
prop.setIsWritable(true);
return QQmlJSRegisterContent::create(
- jsValueType(), prop, QQmlJSRegisterContent::InvalidLookupIndex, lookupIndex,
+ prop, QQmlJSRegisterContent::InvalidLookupIndex, lookupIndex,
QQmlJSRegisterContent::GenericObjectProperty, jsValueType());
}
if (type.isImportNamespace()) {
@@ -1656,7 +1744,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::valueType(const QQmlJSRegisterContent
property.setType(value);
return QQmlJSRegisterContent::create(
- storedType(value), property, QQmlJSRegisterContent::InvalidLookupIndex,
+ property, QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::ListValue, scope);
}
@@ -1667,7 +1755,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::returnType(
Q_ASSERT(variant == QQmlJSRegisterContent::MethodReturnValue
|| variant == QQmlJSRegisterContent::JavaScriptReturnValue);
return QQmlJSRegisterContent::create(
- storedType(type), type, QQmlJSRegisterContent::InvalidLookupIndex, variant, scope);
+ type, QQmlJSRegisterContent::InvalidLookupIndex, variant, scope);
}
QQmlJSRegisterContent QQmlJSTypeResolver::iteratorPointer(
@@ -1676,30 +1764,24 @@ QQmlJSRegisterContent QQmlJSTypeResolver::iteratorPointer(
{
const QQmlJSScope::ConstPtr value = (type == QQmlJS::AST::ForEachType::In)
? m_int32Type
- : containedType(valueType(listType));
+ : valueType(listType).containedType();
QQmlJSScope::ConstPtr iteratorPointer = type == QQmlJS::AST::ForEachType::In
? m_forInIteratorPtr
: m_forOfIteratorPtr;
- const QQmlJSScope::ConstPtr listContained = containedType(listType);
+ const QQmlJSScope::ConstPtr listContained = listType.containedType();
QQmlJSMetaProperty prop;
prop.setPropertyName(u"<>"_s);
prop.setTypeName(iteratorPointer->internalName());
prop.setType(iteratorPointer);
return QQmlJSRegisterContent::create(
- storedType(iteratorPointer), prop, lookupIndex,
+ prop, lookupIndex,
QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::ListIterator,
listContained);
}
-bool QQmlJSTypeResolver::registerIsStoredIn(
- const QQmlJSRegisterContent &reg, const QQmlJSScope::ConstPtr &type) const
-{
- return equals(reg.storedType(), type);
-}
-
bool QQmlJSTypeResolver::registerContains(const QQmlJSRegisterContent &reg,
const QQmlJSScope::ConstPtr &type) const
{
@@ -1760,20 +1842,20 @@ QQmlJSRegisterContent QQmlJSTypeResolver::convert(
{
if (from.isConversion()) {
return QQmlJSRegisterContent::create(
- to.storedType(), from.conversionOrigins(), containedType(to),
+ from.conversionOrigins(), to.containedType(),
to.scopeType() ? to.scopeType() : from.conversionResultScope(),
from.variant(), from.scopeType());
}
return QQmlJSRegisterContent::create(
- to.storedType(), QList<QQmlJSScope::ConstPtr>{containedType(from)},
- containedType(to), to.scopeType(), from.variant(), from.scopeType());
+ QList<QQmlJSScope::ConstPtr>{from.containedType()},
+ to.containedType(), to.scopeType(), from.variant(), from.scopeType());
}
QQmlJSRegisterContent QQmlJSTypeResolver::cast(
const QQmlJSRegisterContent &from, const QQmlJSScope::ConstPtr &to) const
{
- return from.castTo(to).storedIn(storedType(to));
+ return from.castTo(to);
}
QQmlJSScope::ConstPtr QQmlJSTypeResolver::comparableType(const QQmlJSScope::ConstPtr &type) const
diff --git a/src/qmlcompiler/qqmljstyperesolver_p.h b/src/qmlcompiler/qqmljstyperesolver_p.h
index 9961c24842..aecd08f77e 100644
--- a/src/qmlcompiler/qqmljstyperesolver_p.h
+++ b/src/qmlcompiler/qqmljstyperesolver_p.h
@@ -107,6 +107,13 @@ public:
const QQmlJSRegisterContent &left,
const QQmlJSRegisterContent &right) const;
+ QQmlJSScope::ConstPtr typeForId(
+ const QQmlJSScope::ConstPtr &scope, const QString &name,
+ QQmlJSScopesByIdOptions options = Default) const
+ {
+ return m_objectsById.scope(name, scope, options);
+ }
+
enum class UnaryOperator { Not, Plus, Minus, Increment, Decrement, Complement };
QQmlJSRegisterContent typeForArithmeticUnaryOperation(
UnaryOperator op, const QQmlJSRegisterContent &operand) const;
@@ -129,9 +136,15 @@ public:
QQmlJSRegisterContent builtinType(const QQmlJSScope::ConstPtr &type) const;
QQmlJSRegisterContent globalType(const QQmlJSScope::ConstPtr &type) const;
- QQmlJSRegisterContent scopedType(const QQmlJSScope::ConstPtr &scope, const QString &name,
- int lookupIndex = QQmlJSRegisterContent::InvalidLookupIndex,
- QQmlJSScopesByIdOptions options = Default) const;
+ QQmlJSScope::ConstPtr scopedType(
+ const QQmlJSScope::ConstPtr &scope, const QString &name,
+ QQmlJSScopesByIdOptions options = Default) const;
+
+ QQmlJSRegisterContent scopedType(
+ const QQmlJSRegisterContent &scope, const QString &name,
+ int lookupIndex = QQmlJSRegisterContent::InvalidLookupIndex,
+ QQmlJSScopesByIdOptions options = Default) const;
+
QQmlJSRegisterContent memberType(
const QQmlJSRegisterContent &type, const QString &name,
int lookupIndex = QQmlJSRegisterContent::InvalidLookupIndex) const;
@@ -144,13 +157,8 @@ public:
const QQmlJSRegisterContent &listType, QQmlJS::AST::ForEachType type,
int lookupIndex) const;
- bool registerIsStoredIn(const QQmlJSRegisterContent &reg,
- const QQmlJSScope::ConstPtr &type) const;
bool registerContains(const QQmlJSRegisterContent &reg,
const QQmlJSScope::ConstPtr &type) const;
- QQmlJSScope::ConstPtr containedType(const QQmlJSRegisterContent &container) const;
- QString containedTypeName(const QQmlJSRegisterContent &container,
- bool useFancyName = false) const;
QQmlJSRegisterContent tracked(const QQmlJSRegisterContent &type) const;
QQmlJSRegisterContent original(const QQmlJSRegisterContent &type) const;
@@ -224,6 +232,7 @@ public:
bool isTriviallyCopyable(const QQmlJSScope::ConstPtr &type) const;
bool inherits(const QQmlJSScope::ConstPtr &derived, const QQmlJSScope::ConstPtr &base) const;
+ QQmlJSLogger *logger() const { return m_logger; }
protected:
@@ -241,11 +250,15 @@ protected:
const QQmlJSRegisterContent &origin,
QQmlJSScope::ConstPtr (QQmlJSTypeResolver::*op)(const QQmlJSScope::ConstPtr &) const) const;
+ QQmlJSScope::ConstPtr containedTypeForName(const QString &name) const;
QQmlJSRegisterContent registerContentForName(
const QString &name,
const QQmlJSScope::ConstPtr &scopeType = QQmlJSScope::ConstPtr(),
bool hasObjectModuelPrefix = false) const;
+ QQmlJSScope::ConstPtr resolveParentProperty(
+ const QString &name, const QQmlJSScope::ConstPtr &base,
+ const QQmlJSScope::ConstPtr &propType) const;
QQmlJSScope::ConstPtr m_voidType;
QQmlJSScope::ConstPtr m_emptyType;
@@ -317,11 +330,14 @@ protected:
QQmlJSTypeResolver expects to be outlived by its importer and mapper. It crashes when its importer
or mapper gets destructed. Therefore, you can use this struct to extend the lifetime of its
dependencies in case you need to store the resolver as a class member.
+QQmlJSTypeResolver also expects to be outlived by the logger used by the importvisitor, while the
+importvisitor actually does not and will not outlive the QQmlJSTypeResolver.
*/
struct QQmlJSTypeResolverDependencies
{
std::shared_ptr<QQmlJSImporter> importer;
std::shared_ptr<QQmlJSResourceFileMapper> mapper;
+ std::shared_ptr<QQmlJSLogger> logger;
};
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljsutils.cpp b/src/qmlcompiler/qqmljsutils.cpp
index c6eb09b313..6de8741f1b 100644
--- a/src/qmlcompiler/qqmljsutils.cpp
+++ b/src/qmlcompiler/qqmljsutils.cpp
@@ -80,10 +80,7 @@ QQmlJSUtils::ResolvedAlias QQmlJSUtils::resolveAlias(const QQmlJSTypeResolver *t
{
return ::resolveAlias(
[&](const QString &id, const QQmlJSScope::ConstPtr &referrer) {
- const QQmlJSRegisterContent content = typeResolver->scopedType(referrer, id);
- if (content.variant() == QQmlJSRegisterContent::ObjectById)
- return content.type();
- return QQmlJSScope::ConstPtr();
+ return typeResolver->typeForId(referrer, id);
},
property, owner, visitor);
}
diff --git a/src/qmlcompiler/qqmljsutils_p.h b/src/qmlcompiler/qqmljsutils_p.h
index eaa834bec9..c23399e9ae 100644
--- a/src/qmlcompiler/qqmljsutils_p.h
+++ b/src/qmlcompiler/qqmljsutils_p.h
@@ -21,10 +21,12 @@
#include "qqmljsscope_p.h"
#include "qqmljsmetatypes_p.h"
+#include <QtCore/qdir.h>
#include <QtCore/qstack.h>
#include <QtCore/qstring.h>
-#include <QtCore/qstringview.h>
#include <QtCore/qstringbuilder.h>
+#include <QtCore/qstringview.h>
+
#include <QtQml/private/qqmlsignalnames_p.h>
#include <private/qduplicatetracker_p.h>
@@ -200,7 +202,7 @@ struct Q_QMLCOMPILER_EXPORT QQmlJSUtils
const AliasResolutionVisitor &visitor);
template<typename QQmlJSScopePtr, typename Action>
- static bool searchBaseAndExtensionTypes(QQmlJSScopePtr type, const Action &check)
+ static bool searchBaseAndExtensionTypes(const QQmlJSScopePtr &type, const Action &check)
{
if (!type)
return false;
@@ -372,6 +374,13 @@ struct Q_QMLCOMPILER_EXPORT QQmlJSUtils
auto erase = std::unique(container.begin(), container.end());
container.erase(erase, container.end());
}
+
+ static QStringList cleanPaths(QStringList &&paths)
+ {
+ for (QString &path : paths)
+ path = QDir::cleanPath(path);
+ return std::move(paths);
+ }
};
bool Q_QMLCOMPILER_EXPORT canStrictlyCompareWithVar(
diff --git a/src/qmldom/qqmldomastcreator.cpp b/src/qmldom/qqmldomastcreator.cpp
index 67e3acff1c..7add90bf0a 100644
--- a/src/qmldom/qqmldomastcreator.cpp
+++ b/src/qmldom/qqmldomastcreator.cpp
@@ -28,7 +28,7 @@
#include <variant>
#include <vector>
-static Q_LOGGING_CATEGORY(creatorLog, "qt.qmldom.astcreator", QtWarningMsg);
+Q_STATIC_LOGGING_CATEGORY(creatorLog, "qt.qmldom.astcreator", QtWarningMsg);
/*
Avoid crashing on files with JS-elements that are not implemented yet.
@@ -643,8 +643,101 @@ void QQmlDomAstCreator::endVisit(AST::UiPublicMember *el)
removeCurrentNode({});
}
+void QQmlDomAstCreator::endVisit(AST::FormalParameterList *list)
+{
+ endVisitForLists(list);
+}
+
+bool QQmlDomAstCreator::visit(AST::FunctionExpression *)
+{
+ ++m_nestedFunctionDepth;
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+ScriptElementVariant QQmlDomAstCreator::prepareBodyForFunction(AST::FunctionExpression *fExpression)
+{
+ Q_ASSERT(!scriptNodeStack.isEmpty() || !fExpression->body);
+
+ if (fExpression->body) {
+ if (currentScriptNodeEl().isList()) {
+ // It is more intuitive to have functions with a block as a body instead of a
+ // list.
+ auto body = std::make_shared<ScriptElements::BlockStatement>(
+ combineLocations(fExpression->lbraceToken, fExpression->rbraceToken));
+ body->setStatements(currentScriptNodeEl().takeList());
+ if (auto semanticScope = body->statements().semanticScope())
+ body->setSemanticScope(semanticScope);
+ auto result = ScriptElementVariant::fromElement(body);
+ removeCurrentScriptNode({});
+ return result;
+ } else {
+ auto result = currentScriptNodeEl().takeVariant();
+ removeCurrentScriptNode({});
+ return result;
+ }
+ Q_UNREACHABLE_RETURN({});
+ }
+
+ // for convenience purposes: insert an empty BlockStatement
+ auto body = std::make_shared<ScriptElements::BlockStatement>(
+ combineLocations(fExpression->lbraceToken, fExpression->rbraceToken));
+ return ScriptElementVariant::fromElement(body);
+}
+
+void QQmlDomAstCreator::endVisit(AST::FunctionExpression *fExpression)
+{
+ --m_nestedFunctionDepth;
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(fExpression, DomType::ScriptFunctionExpression);
+ if (fExpression->identifierToken.isValid())
+ current->addLocation(IdentifierRegion, fExpression->identifierToken);
+ if (fExpression->functionToken.isValid())
+ current->addLocation(FunctionKeywordRegion, fExpression->functionToken);
+ if (fExpression->lparenToken.isValid())
+ current->addLocation(LeftParenthesisRegion, fExpression->lparenToken);
+ if (fExpression->rparenToken.isValid())
+ current->addLocation(RightParenthesisRegion, fExpression->rparenToken);
+ if (fExpression->lbraceToken.isValid())
+ current->addLocation(LeftBraceRegion, fExpression->lbraceToken);
+ if (fExpression->rbraceToken.isValid())
+ current->addLocation(RightBraceRegion, fExpression->rbraceToken);
+ if (fExpression->typeAnnotation) {
+ current->addLocation(TypeIdentifierRegion,
+ combineLocations(fExpression->typeAnnotation->type));
+ }
+
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() && fExpression->body);
+ current->insertChild(Fields::body, prepareBodyForFunction(fExpression));
+
+ if (fExpression->typeAnnotation) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::returnType, currentScriptNodeEl().takeVariant());
+ scriptNodeStack.removeLast();
+ }
+ if (fExpression->formals) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ current->insertChild(Fields::parameters, currentScriptNodeEl().takeList());
+ scriptNodeStack.removeLast();
+ }
+
+ if (!fExpression->name.isEmpty())
+ current->insertValue(Fields::name, fExpression->name);
+
+ pushScriptElement(current);
+}
+
bool QQmlDomAstCreator::visit(AST::FunctionDeclaration *fDef)
{
+ // Treat nested functions as (named) lambdas instead of Qml Object methods.
+ if (m_nestedFunctionDepth > 0) {
+ return visit(static_cast<FunctionExpression *>(fDef));
+ }
+ ++m_nestedFunctionDepth;
const QStringView code(qmlFilePtr->code());
MethodInfo m;
m.name = fDef->name.toString();
@@ -756,6 +849,12 @@ static void setFormalParameterKind(ScriptElementVariant &variant)
void QQmlDomAstCreator::endVisit(AST::FunctionDeclaration *fDef)
{
+ // Treat nested functions as (named) lambdas instead of Qml Object methods.
+ if (m_nestedFunctionDepth > 1) {
+ endVisit(static_cast<FunctionExpression *>(fDef));
+ return;
+ }
+ --m_nestedFunctionDepth;
MethodInfo &m = std::get<MethodInfo>(currentNode().value);
const FileLocations::Tree bodyTree =
FileLocations::ensure(currentNodeEl().fileLocations, Path().field(Fields::body));
@@ -764,30 +863,9 @@ void QQmlDomAstCreator::endVisit(AST::FunctionDeclaration *fDef)
if (!m_enableScriptExpressions)
return;
- if (fDef->body) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
- if (currentScriptNodeEl().isList()) {
- // It is more intuitive to have functions with a block as a body instead of a
- // list.
- auto body = std::make_shared<ScriptElements::BlockStatement>(
- combineLocations(fDef->lbraceToken, fDef->rbraceToken));
- body->setStatements(currentScriptNodeEl().takeList());
- if (auto semanticScope = body->statements().semanticScope())
- body->setSemanticScope(semanticScope);
- m.body->setScriptElement(finalizeScriptExpression(
- ScriptElementVariant::fromElement(body), bodyPath, bodyTree));
- } else {
- m.body->setScriptElement(finalizeScriptExpression(
- currentScriptNodeEl().takeVariant(), bodyPath, bodyTree));
- }
- removeCurrentScriptNode({});
- } else {
- // for convenience purposes: insert an empty BlockStatement
- auto body = std::make_shared<ScriptElements::BlockStatement>(
- combineLocations(fDef->lbraceToken, fDef->rbraceToken));
- m.body->setScriptElement(finalizeScriptExpression(ScriptElementVariant::fromElement(body),
- bodyPath, bodyTree));
- }
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() && fDef->body);
+ m.body->setScriptElement(
+ finalizeScriptExpression(prepareBodyForFunction(fDef), bodyPath, bodyTree));
if (fDef->typeAnnotation) {
auto argLoc = FileLocations::ensure(nodeStack.last().fileLocations,
@@ -795,30 +873,29 @@ void QQmlDomAstCreator::endVisit(AST::FunctionDeclaration *fDef)
AttachedInfo::PathType::Relative);
const Path pathToReturnType = Path().field(Fields::scriptElement);
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
ScriptElementVariant variant = currentScriptNodeEl().takeVariant();
finalizeScriptExpression(variant, pathToReturnType, argLoc);
m.returnType->setScriptElement(variant);
removeCurrentScriptNode({});
}
- std::vector<FormalParameterList *> reversedInitializerExpressions;
- for (auto it = fDef->formals; it; it = it->next) {
- reversedInitializerExpressions.push_back(it);
- }
- const size_t size = reversedInitializerExpressions.size();
- for (size_t idx = size - 1; idx < size; --idx) {
- auto argLoc = FileLocations::ensure(
- nodeStack.last().fileLocations,
- Path().field(Fields::parameters).index(idx).field(Fields::value),
- AttachedInfo::PathType::Relative);
- const Path pathToArgument = Path().field(Fields::scriptElement);
-
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
- ScriptElementVariant variant = currentScriptNodeEl().takeVariant();
- setFormalParameterKind(variant);
- finalizeScriptExpression(variant, pathToArgument, argLoc);
- m.parameters[idx].value->setScriptElement(variant);
- removeCurrentScriptNode({});
+ if (fDef->formals) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
+ const auto parameterList = scriptNodeStack.takeLast().takeList();
+ const auto &parameterQList = parameterList.qList();
+ size_t size = (size_t)parameterQList.size();
+ for (size_t idx = size - 1; idx < size; --idx) {
+ auto argLoc = FileLocations::ensure(
+ nodeStack.last().fileLocations,
+ Path().field(Fields::parameters).index(idx).field(Fields::value),
+ AttachedInfo::PathType::Relative);
+ const Path pathToArgument = Path().field(Fields::scriptElement);
+
+ ScriptElementVariant variant = parameterQList[idx];
+ setFormalParameterKind(variant);
+ finalizeScriptExpression(variant, pathToArgument, argLoc);
+ m.parameters[idx].value->setScriptElement(variant);
+ }
}
// there should be no more uncollected script elements
@@ -1179,30 +1256,9 @@ void QQmlDomAstCreator::endVisit(AST::UiArrayBinding *)
removeCurrentNode(DomType::Binding);
}
-bool QQmlDomAstCreator::visit(AST::ArgumentList *list)
+void QQmlDomAstCreator::endVisit(AST::ArgumentList *list)
{
- if (!m_enableScriptExpressions)
- return false;
-
- auto currentList = makeScriptList(list);
-
- for (auto it = list; it; it = it->next) {
- Node::accept(it->expression, this);
- if (!m_enableScriptExpressions)
- return false;
-
- if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) {
- Q_SCRIPTELEMENT_DISABLE();
- return false;
- }
- currentList.append(scriptNodeStack.last().takeVariant());
- scriptNodeStack.removeLast();
- }
-
- pushScriptElement(currentList);
-
- return false; // return false because we already iterated over the children using the custom
- // iteration above
+ endVisitForLists(list);
}
bool QQmlDomAstCreator::visit(AST::UiParameterList *)
@@ -1210,65 +1266,19 @@ bool QQmlDomAstCreator::visit(AST::UiParameterList *)
return false; // do not create script node for Ui stuff
}
-bool QQmlDomAstCreator::visit(AST::PatternElementList *list)
+void QQmlDomAstCreator::endVisit(AST::PatternElementList *list)
{
- if (!m_enableScriptExpressions)
- return false;
-
- auto currentList = makeScriptList(list);
-
- for (auto it = list; it; it = it->next) {
- if (it->elision) {
- Node::accept(it->elision, this);
- if (scriptNodeStack.empty() || !scriptNodeStack.last().isList()) {
- Q_SCRIPTELEMENT_DISABLE();
- return false;
- }
- currentList.append(scriptNodeStack.last().takeList());
- scriptNodeStack.removeLast();
- }
- if (it->element) {
- Node::accept(it->element, this);
- if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) {
- Q_SCRIPTELEMENT_DISABLE();
- return false;
- }
- currentList.append(scriptNodeStack.last().takeVariant());
- scriptNodeStack.removeLast();
- }
- }
-
- pushScriptElement(currentList);
-
- return false; // return false because we already iterated over the children using the custom
- // iteration above
+ endVisitForLists<AST::PatternElementList>(list, [](AST::PatternElementList *current) {
+ int toCollect = 0;
+ toCollect += bool(current->elision);
+ toCollect += bool(current->element);
+ return toCollect;
+ });
}
-bool QQmlDomAstCreator::visit(AST::PatternPropertyList *list)
+void QQmlDomAstCreator::endVisit(AST::PatternPropertyList *list)
{
- if (!m_enableScriptExpressions)
- return false;
-
- auto currentList = makeScriptList(list);
-
- for (auto it = list; it; it = it->next) {
- if (it->property) {
- Node::accept(it->property, this);
- if (!m_enableScriptExpressions)
- return false;
- if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) {
- Q_SCRIPTELEMENT_DISABLE();
- return false;
- }
- currentList.append(scriptNodeStack.last().takeVariant());
- scriptNodeStack.removeLast();
- }
- }
-
- pushScriptElement(currentList);
-
- return false; // return false because we already iterated over the children using the custom
- // iteration above
+ endVisitForLists(list);
}
/*!
@@ -1320,7 +1330,9 @@ void QQmlDomAstCreator::endVisit(AST::UiEnumDeclaration *)
bool QQmlDomAstCreator::visit(AST::UiEnumMemberList *el)
{
- EnumItem it(el->member.toString(), el->value);
+ EnumItem it(el->member.toString(), el->value,
+ el->valueToken.isValid() ? EnumItem::ValueKind::ExplicitValue
+ : EnumItem::ValueKind::ImplicitValue);
EnumDecl &eDecl = std::get<EnumDecl>(currentNode().value);
Path itPathFromDecl = eDecl.addValue(it);
const auto map = createMap(DomType::EnumItem, itPathFromDecl, nullptr);
@@ -1459,28 +1471,9 @@ void QQmlDomAstCreator::throwRecursionDepthError()
tr("Maximum statement or expression depth exceeded in QmlDomAstCreator")));
}
-bool QQmlDomAstCreator::visit(AST::StatementList *)
-{
- if (!m_enableScriptExpressions)
- return false;
-
- return true;
-}
-
void QQmlDomAstCreator::endVisit(AST::StatementList *list)
{
- if (!m_enableScriptExpressions)
- return;
-
- auto current = makeScriptList(list);
-
- for (auto it = list; it; it = it->next) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
- current.append(scriptNodeStack.takeLast().takeVariant());
- }
-
- current.reverse();
- pushScriptElement(current);
+ endVisitForLists(list);
}
bool QQmlDomAstCreator::visit(AST::BinaryExpression *)
@@ -1498,10 +1491,10 @@ void QQmlDomAstCreator::endVisit(AST::BinaryExpression *exp)
auto current = makeScriptElement<ScriptElements::BinaryExpression>(exp);
current->addLocation(OperatorTokenRegion, exp->operatorToken);
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setRight(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setLeft(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
@@ -1524,7 +1517,7 @@ void QQmlDomAstCreator::endVisit(AST::Block *block)
auto current = makeScriptElement<ScriptElements::BlockStatement>(block);
if (block->statements) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->setStatements(currentScriptNodeEl().takeList());
removeCurrentScriptNode(DomType::List);
}
@@ -1555,25 +1548,25 @@ void QQmlDomAstCreator::endVisit(AST::ForStatement *forStatement)
current->addLocation(FileLocationRegion::RightParenthesisRegion, forStatement->rparenToken);
if (forStatement->statement) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setBody(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode(std::nullopt);
}
if (forStatement->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setExpression(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode(std::nullopt);
}
if (forStatement->condition) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setCondition(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode(std::nullopt);
}
if (forStatement->declarations) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
auto variableDeclaration = makeGenericScriptElement(forStatement->declarations,
DomType::ScriptVariableDeclaration);
@@ -1593,7 +1586,7 @@ void QQmlDomAstCreator::endVisit(AST::ForStatement *forStatement)
}
if (forStatement->initialiser) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setInitializer(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode(std::nullopt);
}
@@ -1713,30 +1706,33 @@ bool QQmlDomAstCreator::visit(AST::ComputedPropertyName *)
return true;
}
-bool QQmlDomAstCreator::visit(AST::VariableDeclarationList *list)
+template<typename T>
+void QQmlDomAstCreator::endVisitForLists(T *list,
+ const std::function<int(T *)> &scriptElementsPerEntry)
{
if (!m_enableScriptExpressions)
- return false;
-
- auto currentList = makeScriptList(list);
+ return;
+ auto current = makeScriptList(list);
for (auto it = list; it; it = it->next) {
- if (it->declaration) {
- Node::accept(it->declaration, this);
- if (!m_enableScriptExpressions)
- return false;
- if (scriptNodeStack.empty() || scriptNodeStack.last().isList()) {
- Q_SCRIPTELEMENT_DISABLE();
- return false;
- }
- currentList.append(scriptNodeStack.last().takeVariant());
- scriptNodeStack.removeLast();
+ const int entriesToCollect = scriptElementsPerEntry ? scriptElementsPerEntry(it) : 1;
+ for (int i = 0; i < entriesToCollect; ++i) {
+ Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ auto last = scriptNodeStack.takeLast();
+ if (last.isList())
+ current.append(last.takeList());
+ else
+ current.append(last.takeVariant());
}
}
- pushScriptElement(currentList);
- return false; // return false because we already iterated over the children using the custom
- // iteration above
+ current.reverse();
+ pushScriptElement(current);
+}
+
+void QQmlDomAstCreator::endVisit(AST::VariableDeclarationList *list)
+{
+ endVisitForLists(list);
}
bool QQmlDomAstCreator::visit(AST::Elision *list)
@@ -1783,17 +1779,17 @@ void QQmlDomAstCreator::endVisitHelper(
current->insertChild(Fields::identifier, ScriptElementVariant::fromElement(identifier));
}
if (pe->initializer) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::initializer, scriptNodeStack.last().takeVariant());
scriptNodeStack.removeLast();
}
if (pe->typeAnnotation) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::type, scriptNodeStack.last().takeVariant());
scriptNodeStack.removeLast();
}
if (pe->bindingTarget) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::bindingElement, scriptNodeStack.last().takeVariant());
scriptNodeStack.removeLast();
}
@@ -1833,18 +1829,18 @@ void QQmlDomAstCreator::endVisit(AST::IfStatement *ifStatement)
current->addLocation(IfKeywordRegion, ifStatement->ifToken);
if (ifStatement->ko) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setAlternative(scriptNodeStack.last().takeVariant());
scriptNodeStack.removeLast();
}
if (ifStatement->ok) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setConsequence(scriptNodeStack.last().takeVariant());
scriptNodeStack.removeLast();
}
if (ifStatement->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setCondition(scriptNodeStack.last().takeVariant());
scriptNodeStack.removeLast();
}
@@ -1869,7 +1865,7 @@ void QQmlDomAstCreator::endVisit(AST::ReturnStatement *returnStatement)
current->addLocation(ReturnKeywordRegion, returnStatement->returnToken);
if (returnStatement->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setExpression(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -1877,6 +1873,31 @@ void QQmlDomAstCreator::endVisit(AST::ReturnStatement *returnStatement)
pushScriptElement(current);
}
+bool QQmlDomAstCreator::visit(AST::YieldExpression *)
+{
+ if (!m_enableScriptExpressions)
+ return false;
+
+ return true;
+}
+
+void QQmlDomAstCreator::endVisit(AST::YieldExpression *yExpression)
+{
+ if (!m_enableScriptExpressions)
+ return;
+
+ auto current = makeGenericScriptElement(yExpression, DomType::ScriptYieldExpression);
+ current->addLocation(YieldKeywordRegion, yExpression->yieldToken);
+
+ if (yExpression->expression) {
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
+ current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
+ removeCurrentScriptNode({});
+ }
+
+ pushScriptElement(current);
+}
+
bool QQmlDomAstCreator::visit(AST::FieldMemberExpression *)
{
if (!m_enableScriptExpressions)
@@ -1895,7 +1916,7 @@ void QQmlDomAstCreator::endVisit(AST::FieldMemberExpression *expression)
current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->dotToken);
if (expression->base) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setLeft(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -1926,7 +1947,7 @@ void QQmlDomAstCreator::endVisit(AST::ArrayMemberExpression *expression)
current->addLocation(FileLocationRegion::OperatorTokenRegion, expression->lbracketToken);
if (expression->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
// if scriptNodeStack.last() is fieldmember expression, add expression to it instead of
// creating new one
current->setRight(currentScriptNodeEl().takeVariant());
@@ -1934,7 +1955,7 @@ void QQmlDomAstCreator::endVisit(AST::ArrayMemberExpression *expression)
}
if (expression->base) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setLeft(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -1960,7 +1981,7 @@ void QQmlDomAstCreator::endVisit(AST::CallExpression *exp)
current->addLocation(RightParenthesisRegion, exp->rparenToken);
if (exp->arguments) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->insertChild(Fields::arguments, currentScriptNodeEl().takeList());
removeCurrentScriptNode({});
} else {
@@ -1970,7 +1991,7 @@ void QQmlDomAstCreator::endVisit(AST::CallExpression *exp)
}
if (exp->base) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::callee, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -1994,7 +2015,7 @@ void QQmlDomAstCreator::endVisit(AST::ArrayPattern *exp)
auto current = makeGenericScriptElement(exp, DomType::ScriptArray);
if (exp->elements) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
list.replaceKindForGenericChildren(DomType::ScriptPattern, DomType::ScriptArrayEntry);
current->insertChild(Fields::elements, std::move(list));
@@ -2025,7 +2046,7 @@ void QQmlDomAstCreator::endVisit(AST::ObjectPattern *exp)
auto current = makeGenericScriptElement(exp, DomType::ScriptObject);
if (exp->properties) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->insertChild(Fields::properties, currentScriptNodeEl().takeList());
removeCurrentScriptNode({});
} else {
@@ -2060,7 +2081,7 @@ void QQmlDomAstCreator::endVisit(AST::PatternProperty *exp)
return;
if (exp->name) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::name, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2085,7 +2106,7 @@ void QQmlDomAstCreator::endVisit(AST::VariableStatement *statement)
current->addLocation(FileLocationRegion::TypeIdentifierRegion, statement->declarationKindToken);
if (statement->declarations) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
ScriptElements::ScriptList list = currentScriptNodeEl().takeList();
list.replaceKindForGenericChildren(DomType::ScriptPattern,
@@ -2145,7 +2166,7 @@ void QQmlDomAstCreator::endVisit(AST::DefaultClause *exp)
current->addLocation(ColonTokenRegion, exp->colonToken);
if (exp->statements) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
removeCurrentScriptNode({});
}
@@ -2171,13 +2192,13 @@ void QQmlDomAstCreator::endVisit(AST::CaseClause *exp)
current->addLocation(FileLocationRegion::ColonTokenRegion, exp->colonToken);
if (exp->statements) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->insertChild(Fields::statements, currentScriptNodeEl().takeList());
removeCurrentScriptNode({});
}
if (exp->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2201,7 +2222,7 @@ void QQmlDomAstCreator::endVisit(AST::CaseClauses *list)
auto current = makeScriptList(list);
for (auto it = list; it; it = it->next) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current.append(scriptNodeStack.takeLast().takeVariant());
}
@@ -2227,19 +2248,19 @@ void QQmlDomAstCreator::endVisit(AST::CaseBlock *exp)
current->addLocation(FileLocationRegion::RightBraceRegion, exp->rbraceToken);
if (exp->moreClauses) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->insertChild(Fields::moreCaseClauses, currentScriptNodeEl().takeList());
removeCurrentScriptNode({});
}
if (exp->defaultClause) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::defaultClause, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (exp->clauses) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptList());
current->insertChild(Fields::caseClauses, currentScriptNodeEl().takeList());
removeCurrentScriptNode({});
}
@@ -2265,12 +2286,12 @@ void QQmlDomAstCreator::endVisit(AST::SwitchStatement *exp)
current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
if (exp->block) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::caseBlock, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (exp->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2297,13 +2318,13 @@ void QQmlDomAstCreator::endVisit(AST::WhileStatement *exp)
current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
if (exp->statement) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (exp->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2331,13 +2352,13 @@ void QQmlDomAstCreator::endVisit(AST::DoWhileStatement *exp)
current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
if (exp->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (exp->statement) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2365,18 +2386,18 @@ void QQmlDomAstCreator::endVisit(AST::ForEachStatement *exp)
current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
if (exp->statement) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::body, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (exp->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (exp->lhs) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::bindingElement, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
@@ -2429,7 +2450,7 @@ void QQmlDomAstCreator::endVisit(AST::TryStatement *statement)
if (auto exp = statement->finallyExpression) {
current->addLocation(FileLocationRegion::FinallyKeywordRegion, exp->finallyToken);
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::finallyBlock, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2439,16 +2460,16 @@ void QQmlDomAstCreator::endVisit(AST::TryStatement *statement)
current->addLocation(FileLocationRegion::LeftParenthesisRegion, exp->lparenToken);
current->addLocation(FileLocationRegion::RightParenthesisRegion, exp->rparenToken);
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::catchBlock, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::catchParameter, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (statement->statement) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::block, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2492,7 +2513,7 @@ void QQmlDomAstCreator::endVisit(AST::ThrowStatement *statement)
current->addLocation(FileLocationRegion::ThrowKeywordRegion, statement->throwToken);
if (statement->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2519,7 +2540,7 @@ void QQmlDomAstCreator::endVisit(AST::LabelledStatement *statement)
if (statement->statement) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::statement, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2566,13 +2587,13 @@ void QQmlDomAstCreator::endVisit(AST::Expression *commaExpression)
current->addLocation(OperatorTokenRegion, commaExpression->commaToken);
if (commaExpression->right) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setRight(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (commaExpression->left) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->setLeft(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2595,19 +2616,19 @@ void QQmlDomAstCreator::endVisit(AST::ConditionalExpression *expression)
current->addLocation(FileLocationRegion::ColonTokenRegion, expression->colonToken);
if (expression->ko) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::alternative, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (expression->ok) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::consequence, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
if (expression->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::condition, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2661,7 +2682,7 @@ QQmlDomAstCreator::makeUnaryExpression(AST::Node *expression, QQmlJS::SourceLoca
current->addLocation(FileLocationRegion::OperatorTokenRegion, operatorToken);
if (hasExpression) {
- if (scriptNodeStack.isEmpty() || scriptNodeStack.last().isList()) {
+ if (!stackHasScriptVariant()) {
Q_SCRIPTELEMENT_DISABLE();
return {};
}
@@ -2882,7 +2903,7 @@ void QQmlDomAstCreator::endVisit(AST::NestedExpression *expression)
current->addLocation(FileLocationRegion::RightParenthesisRegion, expression->rparenToken);
if (expression->expression) {
- Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty() || scriptNodeStack.last().isList());
+ Q_SCRIPTELEMENT_EXIT_IF(!stackHasScriptVariant());
current->insertChild(Fields::expression, currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
@@ -2970,6 +2991,30 @@ void QQmlDomAstCreatorWithQQmlJSScope::setScopeInDomAfterEndvisit()
case DomType::List:
m_domCreator.currentScriptNodeEl().setSemanticScope(scope);
break;
+ case DomType::ScriptFunctionExpression: {
+ // Put the body's scope into the function expression: function expressions will contain
+ // their parents scope instead of their own without this
+ auto element = m_domCreator.currentScriptNodeEl().value;
+ auto scriptElementVariant = std::get_if<ScriptElementVariant>(&element);
+ if (!scriptElementVariant || !scriptElementVariant->data())
+ break;
+ scriptElementVariant->visit([](auto &&e) {
+ using U = std::remove_cv_t<std::remove_reference_t<decltype(e)>>;
+ if (e->kind() != DomType::ScriptFunctionExpression)
+ return;
+
+ if constexpr (std::is_same_v<U,
+ ScriptElement::PointerType<
+ ScriptElements::GenericScriptElement>>) {
+ if (auto bodyPtr = e->elementChild(Fields::body)) {
+ const auto bodyScope = bodyPtr.base()->semanticScope();
+ e->setSemanticScope(bodyScope);
+ }
+ }
+ });
+ break;
+ }
+
// TODO: find which script elements also have a scope and implement them here
default:
break;
@@ -3013,11 +3058,13 @@ void QQmlDomAstCreatorWithQQmlJSScope::setScopeInDomBeforeEndvisit()
// property definition has a binding, like `property int i: 45` for
// example), then the property definition scope is the parent of the current
// scope.
- e.setSemanticScope(scope->scopeType() == QQmlSA::ScopeType::JSFunctionScope
+ const bool usePropertyDefinitionScopeInsteadOfTheBindingScope =
+ scope->scopeType() == QQmlSA::ScopeType::JSFunctionScope
+ && scope->parentScope()
+ && scope->parentScope()->scopeType() == QQmlSA::ScopeType::QMLScope;
+ e.setSemanticScope(usePropertyDefinitionScopeInsteadOfTheBindingScope
? scope->parentScope()
: scope);
- Q_ASSERT(e.semanticScope()
- && e.semanticScope()->scopeType() == QQmlSA::ScopeType::QMLScope);
}
},
m_domCreator.currentNodeEl(1).item.value);
diff --git a/src/qmldom/qqmldomastcreator_p.h b/src/qmldom/qqmldomastcreator_p.h
index 8176721d7e..8a050b4c2d 100644
--- a/src/qmldom/qqmldomastcreator_p.h
+++ b/src/qmldom/qqmldomastcreator_p.h
@@ -135,6 +135,7 @@ private:
QList<ScriptStackElement> scriptNodeStack;
QVector<int> arrayBindingLevels;
FileLocations::Tree rootMap;
+ int m_nestedFunctionDepth = 0;
bool m_enableScriptExpressions = false;
bool m_loadFileLazily = false;
@@ -321,6 +322,13 @@ public:
bool visit(AST::UiPublicMember *el) override;
void endVisit(AST::UiPublicMember *el) override;
+private:
+ ScriptElementVariant prepareBodyForFunction(AST::FunctionExpression *fExpression);
+
+public:
+ bool visit(AST::FunctionExpression *el) override;
+ void endVisit(AST::FunctionExpression *) override;
+
bool visit(AST::FunctionDeclaration *el) override;
void endVisit(AST::FunctionDeclaration *) override;
@@ -364,6 +372,9 @@ public:
bool visit(AST::Block *block) override;
void endVisit(AST::Block *) override;
+ bool visit(AST::YieldExpression *block) override;
+ void endVisit(AST::YieldExpression *) override;
+
bool visit(AST::ReturnStatement *block) override;
void endVisit(AST::ReturnStatement *) override;
@@ -497,17 +508,20 @@ public:
bool visit(AST::NestedExpression *) override;
void endVisit(AST::NestedExpression *) override;
- // lists of stuff whose children do not need a qqmljsscope: visitation order can be custom
- bool visit(AST::ArgumentList *) override;
+
+ // lists of stuff whose children don't need a qqmljsscope: visitation order can be custom
bool visit(AST::UiParameterList *) override;
- bool visit(AST::PatternElementList *) override;
- bool visit(AST::PatternPropertyList *) override;
- bool visit(AST::VariableDeclarationList *vdl) override;
bool visit(AST::Elision *elision) override;
+
// lists of stuff whose children need a qqmljsscope: visitation order cannot be custom
- bool visit(AST::StatementList *list) override;
void endVisit(AST::StatementList *list) override;
+ void endVisit(AST::VariableDeclarationList *vdl) override;
+ void endVisit(AST::ArgumentList *) override;
+ void endVisit(AST::PatternElementList *) override;
+ void endVisit(AST::PatternPropertyList *) override;
+ void endVisit(AST::FormalParameterList *el) override;
+
// literals and ids
bool visit(AST::IdentifierExpression *expression) override;
@@ -524,6 +538,19 @@ public:
void throwRecursionDepthError() override;
+ bool stackHasScriptVariant() const
+ {
+ return !scriptNodeStack.isEmpty() && !scriptNodeStack.last().isList();
+ }
+ bool stackHasScriptList() const
+ {
+ return !scriptNodeStack.isEmpty() && scriptNodeStack.last().isList();
+ }
+
+private:
+ template<typename T>
+ void endVisitForLists(T *list, const std::function<int(T *)> &scriptElementsPerEntry = {});
+
public:
friend class QQmlDomAstCreatorWithQQmlJSScope;
};
@@ -567,8 +594,9 @@ private:
template<typename U, typename... V>
using IsInList = std::disjunction<std::is_same<U, V>...>;
template<typename U>
- using RequiresCustomIteration = IsInList<U, AST::PatternElementList, AST::PatternPropertyList,
- AST::FormalParameterList>;
+ using RequiresCustomIteration =
+ IsInList<U, AST::PatternElementList, AST::PatternPropertyList, AST::FormalParameterList,
+ AST::VariableDeclarationList>;
enum VisitorKind : bool { DomCreator, ScopeCreator };
/*! \internal
@@ -592,7 +620,7 @@ private:
void customListIteration(T *t)
{
static_assert(RequiresCustomIteration<T>::value);
- for (auto it = t; it; it = it->next) {
+ for (T* it = t; it; it = it->next) {
if constexpr (std::is_same_v<T, AST::PatternElementList>) {
AST::Node::accept(it->elision, this);
AST::Node::accept(it->element, this);
@@ -600,6 +628,13 @@ private:
AST::Node::accept(it->property, this);
} else if constexpr (std::is_same_v<T, AST::FormalParameterList>) {
AST::Node::accept(it->element, this);
+ } else if constexpr (std::is_same_v<T, AST::VariableDeclarationList>) {
+ AST::Node::accept(it->declaration, this);
+ } else if constexpr (std::is_same_v<T, AST::ArgumentList>) {
+ AST::Node::accept(it->expression, this);
+ } else if constexpr (std::is_same_v<T, AST::PatternElementList>) {
+ AST::Node::accept(it->elision, this);
+ AST::Node::accept(it->element, this);
} else {
Q_UNREACHABLE();
}
diff --git a/src/qmldom/qqmldomcodeformatter.cpp b/src/qmldom/qqmldomcodeformatter.cpp
index 5660025fd8..27279ce7c0 100644
--- a/src/qmldom/qqmldomcodeformatter.cpp
+++ b/src/qmldom/qqmldomcodeformatter.cpp
@@ -6,7 +6,7 @@
#include <QLoggingCategory>
#include <QMetaEnum>
-static Q_LOGGING_CATEGORY(formatterLog, "qt.qmldom.formatter", QtWarningMsg);
+Q_STATIC_LOGGING_CATEGORY(formatterLog, "qt.qmldom.formatter", QtWarningMsg);
QT_BEGIN_NAMESPACE
namespace QQmlJS {
diff --git a/src/qmldom/qqmldomcomments.cpp b/src/qmldom/qqmldomcomments.cpp
index 308467b99b..8e94758b57 100644
--- a/src/qmldom/qqmldomcomments.cpp
+++ b/src/qmldom/qqmldomcomments.cpp
@@ -17,7 +17,7 @@
#include <variant>
-static Q_LOGGING_CATEGORY(commentsLog, "qt.qmldom.comments", QtWarningMsg);
+Q_STATIC_LOGGING_CATEGORY(commentsLog, "qt.qmldom.comments", QtWarningMsg);
QT_BEGIN_NAMESPACE
namespace QQmlJS {
diff --git a/src/qmldom/qqmldomconstants_p.h b/src/qmldom/qqmldomconstants_p.h
index 469facd4b2..ac5f8f67c4 100644
--- a/src/qmldom/qqmldomconstants_p.h
+++ b/src/qmldom/qqmldomconstants_p.h
@@ -227,6 +227,8 @@ enum class DomType {
ScriptConditionalExpression,
ScriptEmptyStatement,
ScriptParenthesizedExpression,
+ ScriptFunctionExpression,
+ ScriptYieldExpression,
ScriptElementStop, // marker to check if a DomType is a scriptelement or not
};
@@ -394,6 +396,7 @@ enum FileLocationRegion : int {
TypeIdentifierRegion,
VersionRegion,
WhileKeywordRegion,
+ YieldKeywordRegion,
};
Q_ENUM_NS(FileLocationRegion);
diff --git a/src/qmldom/qqmldomelements.cpp b/src/qmldom/qqmldomelements.cpp
index 0fe5c3eb36..348984172f 100644
--- a/src/qmldom/qqmldomelements.cpp
+++ b/src/qmldom/qqmldomelements.cpp
@@ -2017,23 +2017,12 @@ void EnumItem::writeOut(const DomItem &self, OutWriter &ow) const
{
ow.ensureNewline();
ow.writeRegion(IdentifierRegion, name());
- bool hasDefaultValue = false;
index_type myIndex = self.pathFromOwner().last().headIndex();
- if (myIndex == 0)
- hasDefaultValue = value() == 0;
- else if (myIndex > 0)
- hasDefaultValue = value()
- == self.container()
- .index(myIndex - 1)
- .field(Fields::value)
- .value()
- .toDouble(value())
- + 1;
- if (!hasDefaultValue) {
+ if (m_valueKind == ValueKind::ExplicitValue) {
QString v = QString::number(value(), 'f', 0);
if (abs(value() - v.toDouble()) > 1.e-10)
v = QString::number(value());
- ow.space().writeRegion(EqualTokenRegion).space().writeRegion(PragmaValuesRegion, v);
+ ow.space().writeRegion(EqualTokenRegion).space().writeRegion(EnumValueRegion, v);
}
if (myIndex >= 0 && self.container().indexes() != myIndex + 1)
ow.writeRegion(CommaTokenRegion);
diff --git a/src/qmldom/qqmldomelements_p.h b/src/qmldom/qqmldomelements_p.h
index db57da7bb2..95cddbbc32 100644
--- a/src/qmldom/qqmldomelements_p.h
+++ b/src/qmldom/qqmldomelements_p.h
@@ -780,8 +780,14 @@ class QMLDOM_EXPORT EnumItem
{
public:
constexpr static DomType kindValue = DomType::EnumItem;
-
- EnumItem(const QString &name = QString(), int value = 0) : m_name(name), m_value(value) { }
+ enum class ValueKind : quint8 {
+ ImplicitValue,
+ ExplicitValue
+ };
+ EnumItem(const QString &name = QString(), int value = 0, ValueKind valueKind = ValueKind::ImplicitValue)
+ : m_name(name), m_value(value), m_valueKind(valueKind)
+ {
+ }
bool iterateDirectSubpaths(const DomItem &self, DirectVisitor visitor) const;
@@ -794,6 +800,7 @@ public:
private:
QString m_name;
double m_value;
+ ValueKind m_valueKind;
RegionComments m_comments;
};
diff --git a/src/qmldom/qqmldomexternalitems_p.h b/src/qmldom/qqmldomexternalitems_p.h
index 1aa9d765cb..97328b40de 100644
--- a/src/qmldom/qqmldomexternalitems_p.h
+++ b/src/qmldom/qqmldomexternalitems_p.h
@@ -423,6 +423,11 @@ public:
DomCreationOptions creationOptions() const { return lazyMembers().m_creationOptions; }
+ QQmlJSScope::ConstPtr handleForPopulation() const
+ {
+ return m_handleForPopulation;
+ }
+
void setHandleForPopulation(const QQmlJSScope::ConstPtr &scope)
{
m_handleForPopulation = scope;
diff --git a/src/qmldom/qqmldomitem.cpp b/src/qmldom/qqmldomitem.cpp
index b885422c1d..8e4f8acd40 100644
--- a/src/qmldom/qqmldomitem.cpp
+++ b/src/qmldom/qqmldomitem.cpp
@@ -47,7 +47,7 @@ namespace QQmlJS {
namespace Dom {
Q_LOGGING_CATEGORY(writeOutLog, "qt.qmldom.writeOut", QtWarningMsg);
-static Q_LOGGING_CATEGORY(refLog, "qt.qmldom.ref", QtWarningMsg);
+Q_STATIC_LOGGING_CATEGORY(refLog, "qt.qmldom.ref", QtWarningMsg);
template<class... TypeList>
struct CheckDomElementT;
diff --git a/src/qmldom/qqmldomitem_p.h b/src/qmldom/qqmldomitem_p.h
index 50775a1db2..c27fa48c46 100644
--- a/src/qmldom/qqmldomitem_p.h
+++ b/src/qmldom/qqmldomitem_p.h
@@ -56,7 +56,7 @@ namespace Dom {
class Path;
-Q_DECLARE_LOGGING_CATEGORY(writeOutLog);
+QT_DECLARE_EXPORTED_QT_LOGGING_CATEGORY(writeOutLog, QMLDOM_EXPORT);
constexpr bool domTypeIsObjWrap(DomType k);
constexpr bool domTypeIsValueWrap(DomType k);
diff --git a/src/qmldom/qqmldomoutwriter.cpp b/src/qmldom/qqmldomoutwriter.cpp
index 7f4f219cbf..bcfc8ace69 100644
--- a/src/qmldom/qqmldomoutwriter.cpp
+++ b/src/qmldom/qqmldomoutwriter.cpp
@@ -245,6 +245,9 @@ OutWriter &OutWriter::writeRegion(FileLocationRegion region)
case SwitchKeywordRegion:
codeForRegion = u"switch"_s;
break;
+ case YieldKeywordRegion:
+ codeForRegion = u"yield"_s;
+ break;
// not keywords:
case ImportUriRegion:
case IdNameRegion:
diff --git a/src/qmldom/qqmldomreformatter.cpp b/src/qmldom/qqmldomreformatter.cpp
index 95533b61ac..3093a3d4da 100644
--- a/src/qmldom/qqmldomreformatter.cpp
+++ b/src/qmldom/qqmldomreformatter.cpp
@@ -618,6 +618,19 @@ bool ScriptFormatter::visit(ReturnStatement *ast)
return false;
}
+bool ScriptFormatter::visit(YieldExpression *ast)
+{
+ out(ast->yieldToken);
+ if (ast->isYieldStar)
+ out("*");
+ if (ast->expression) {
+ if (ast->yieldToken.isValid())
+ out(" ");
+ accept(ast->expression);
+ }
+ return false;
+}
+
bool ScriptFormatter::visit(ThrowStatement *ast)
{
out(ast->throwToken);
diff --git a/src/qmldom/qqmldomreformatter_p.h b/src/qmldom/qqmldomreformatter_p.h
index e498e14b44..48e2c63881 100644
--- a/src/qmldom/qqmldomreformatter_p.h
+++ b/src/qmldom/qqmldomreformatter_p.h
@@ -134,6 +134,7 @@ protected:
bool visit(AST::BreakStatement *ast) override;
bool visit(AST::ReturnStatement *ast) override;
+ bool visit(AST::YieldExpression *ast) override;
bool visit(AST::ThrowStatement *ast) override;
bool visit(AST::WithStatement *ast) override;
diff --git a/src/qmldom/qqmldomscriptelements.cpp b/src/qmldom/qqmldomscriptelements.cpp
index 4bde2abd09..c0a48e0ce3 100644
--- a/src/qmldom/qqmldomscriptelements.cpp
+++ b/src/qmldom/qqmldomscriptelements.cpp
@@ -108,6 +108,9 @@ bool GenericScriptElement::iterateDirectSubpaths(const DomItem &self, DirectVisi
[&self, &visitor, &it](auto &&e) { return wrap(self, visitor, it->first, e); },
it->second);
}
+ for (auto it = m_values.begin(); it != m_values.end(); ++it) {
+ cont &= self.dvValueField(visitor, it->first, it->second);
+ }
return cont;
}
diff --git a/src/qmldom/qqmldomscriptelements_p.h b/src/qmldom/qqmldomscriptelements_p.h
index b319e7e88f..febf0091c3 100644
--- a/src/qmldom/qqmldomscriptelements_p.h
+++ b/src/qmldom/qqmldomscriptelements_p.h
@@ -16,6 +16,7 @@
//
#include "qqmldomitem_p.h"
+#include "qqmldomelements_p.h"
#include "qqmldomattachedinfo_p.h"
#include "qqmldompath_p.h"
#include <algorithm>
@@ -157,7 +158,7 @@ public:
void append(const ScriptList &list) { m_list.append(list.m_list); }
void reverse() { std::reverse(m_list.begin(), m_list.end()); }
void replaceKindForGenericChildren(DomType oldType, DomType newType);
- const QList<ScriptElementVariant> &qList() { return std::as_const(m_list); };
+ const QList<ScriptElementVariant> &qList() const { return std::as_const(m_list); };
private:
QList<ScriptElementVariant> m_list;
@@ -181,6 +182,21 @@ public:
return m_children.insert(std::make_pair(name, v));
}
+ ScriptElementVariant elementChild(const QQmlJS::Dom::FieldType &field)
+ {
+ auto it = m_children.find(field);
+ if (it == m_children.end())
+ return {};
+ if (!std::holds_alternative<ScriptElementVariant>(it->second))
+ return {};
+ return std::get<ScriptElementVariant>(it->second);
+ }
+
+ void insertValue(QStringView name, const QCborValue &v)
+ {
+ m_values.insert(std::make_pair(name, v));
+ }
+
private:
/*!
\internal
@@ -189,6 +205,8 @@ private:
a sorted map to always iterate the children in the same order.
*/
std::map<QQmlJS::Dom::FieldType, VariantT> m_children;
+ // value fields
+ std::map<QQmlJS::Dom::FieldType, QCborValue> m_values;
DomType m_kind = DomType::Empty;
};
diff --git a/src/qmldom/qqmldomtop.cpp b/src/qmldom/qqmldomtop.cpp
index 8ae836b0a2..cfc20d50ef 100644
--- a/src/qmldom/qqmldomtop.cpp
+++ b/src/qmldom/qqmldomtop.cpp
@@ -1825,44 +1825,19 @@ only works after the constructor call finished.
*/
DomEnvironment::SemanticAnalysis &DomEnvironment::semanticAnalysis()
{
+ // QTBUG-124799: do not create a SemanticAnalysis in a temporary DomEnvironment, and use the one
+ // from the base environment instead.
+ if (m_base) {
+ auto &result = m_base->semanticAnalysis();
+ result.setLoadPaths(m_loadPaths);
+ return result;
+ }
+
if (m_semanticAnalysis)
return *m_semanticAnalysis;
Q_ASSERT(domCreationOptions().testFlag(DomCreationOption::WithSemanticAnalysis));
-
m_semanticAnalysis = SemanticAnalysis(m_loadPaths);
- const auto &importer = m_semanticAnalysis->m_importer;
-
- importer->setImportVisitor([self = weak_from_this(), base = m_base](
- QQmlJS::AST::Node *rootNode, QQmlJSImporter *importer,
- const QQmlJSImporter::ImportVisitorPrerequisites &p) {
- Q_UNUSED(rootNode);
- Q_UNUSED(importer);
-
- // support the "commitToBase" workflow, which does changes in a temporary
- // DomEnvironment. if the current DomEnvironment is temporary (e.g. the weak pointer is
- // null), then we assume that the current DomEnvironment was committed to base and then
- // destructed. Use the base DomEnvironment instead.
- std::shared_ptr<DomEnvironment> envPtr;
- if (auto ptr = self.lock()) {
- envPtr = ptr;
- } else {
- envPtr = base;
- }
- // populate QML File if from implicit import directory
- // use the version in DomEnvironment and do *not* load from disk.
- auto it = envPtr->m_qmlFileWithPath.constFind(p.m_logger->fileName());
- if (it == envPtr->m_qmlFileWithPath.constEnd()) {
- qCDebug(domLog) << "Import visitor tried to lazily load file \""
- << p.m_logger->fileName()
- << "\", but that file was not found in the DomEnvironment. Was this "
- "file not discovered by the Dom's dependency loading mechanism?";
- return;
- }
- const DomItem qmlFile = it.value()->currentItem(DomItem(envPtr));
- envPtr->populateFromQmlFile(MutableDomItem(qmlFile));
- });
-
return *m_semanticAnalysis;
}
@@ -1875,7 +1850,9 @@ DomEnvironment::SemanticAnalysis::SemanticAnalysis(const QStringList &loadPaths)
void DomEnvironment::SemanticAnalysis::setLoadPaths(const QStringList &loadPaths)
{
- // TODO: maybe also update the build paths in m_mapper?
+ if (loadPaths == m_importer->importPaths())
+ return;
+
m_importer->setImportPaths(loadPaths);
}
@@ -1901,12 +1878,18 @@ DomEnvironment::DomEnvironment(const shared_ptr<DomEnvironment> &parent,
void DomEnvironment::addQmlFile(const std::shared_ptr<QmlFile> &file, AddOption options)
{
+ addExternalItem(file, file->canonicalFilePath(), options);
if (domCreationOptions().testFlag(DomCreationOption::WithSemanticAnalysis)) {
const QQmlJSScope::Ptr &handle =
semanticAnalysis().m_importer->importFile(file->canonicalFilePath());
+
+ // force reset the outdated qqmljsscope in case it was already populated
+ QDeferredFactory<QQmlJSScope> newFactory(semanticAnalysis().m_importer.get(),
+ file->canonicalFilePath(),
+ TypeReader{ weak_from_this() });
file->setHandleForPopulation(handle);
+ handle.resetFactory(std::move(newFactory));
}
- addExternalItem(file, file->canonicalFilePath(), options);
}
void DomEnvironment::addQmlDirectory(const std::shared_ptr<QmlDirectory> &file, AddOption options)
@@ -1934,6 +1917,36 @@ void DomEnvironment::addGlobalScope(const std::shared_ptr<GlobalScope> &scope, A
addExternalItem(scope, scope->name(), options);
}
+QList<QQmlJS::DiagnosticMessage>
+DomEnvironment::TypeReader::operator()(QQmlJSImporter *importer, const QString &filePath,
+ const QSharedPointer<QQmlJSScope> &scopeToPopulate)
+{
+ Q_UNUSED(importer);
+ Q_UNUSED(scopeToPopulate);
+
+ const QFileInfo info{ filePath };
+ const QString baseName = info.baseName();
+ scopeToPopulate->setInternalName(baseName.endsWith(QStringLiteral(".ui")) ? baseName.chopped(3)
+ : baseName);
+
+ std::shared_ptr<DomEnvironment> envPtr = m_env.lock();
+ // populate QML File if from implicit import directory
+ // use the version in DomEnvironment and do *not* load from disk.
+ auto it = envPtr->m_qmlFileWithPath.constFind(filePath);
+ if (it == envPtr->m_qmlFileWithPath.constEnd()) {
+ qCDebug(domLog) << "Import visitor tried to lazily load file \"" << filePath
+ << "\", but that file was not found in the DomEnvironment. Was this "
+ "file not discovered by the Dom's dependency loading mechanism?";
+ return { QQmlJS::DiagnosticMessage{
+ u"Could not find file \"%1\" in the Dom."_s.arg(filePath), QtMsgType::QtWarningMsg,
+ SourceLocation{} } };
+ }
+ const DomItem qmlFile = it.value()->currentItem(DomItem(envPtr));
+ envPtr->populateFromQmlFile(MutableDomItem(qmlFile));
+ return {};
+}
+
+
bool DomEnvironment::commitToBase(
const DomItem &self, const shared_ptr<DomEnvironment> &validEnvPtr)
{
@@ -1947,6 +1960,7 @@ bool DomEnvironment::commitToBase(
QMap<QString, std::shared_ptr<ExternalItemInfo<JsFile>>> my_jsFileWithPath;
QMap<QString, std::shared_ptr<ExternalItemInfo<QmltypesFile>>> my_qmltypesFileWithPath;
QHash<Path, std::shared_ptr<LoadInfo>> my_loadInfos;
+ std::optional<SemanticAnalysis> my_semanticAnalysis;
{
QMutexLocker l(mutex());
my_moduleIndexWithUri = m_moduleIndexWithUri;
@@ -1957,10 +1971,11 @@ bool DomEnvironment::commitToBase(
my_jsFileWithPath = m_jsFileWithPath;
my_qmltypesFileWithPath = m_qmltypesFileWithPath;
my_loadInfos = m_loadInfos;
+ my_semanticAnalysis = semanticAnalysis();
}
{
QMutexLocker lBase(base()->mutex()); // be more careful about makeCopy calls with lock?
- m_base->m_semanticAnalysis = m_semanticAnalysis;
+ m_base->m_semanticAnalysis = my_semanticAnalysis;
m_base->m_globalScopeWithName.insert(my_globalScopeWithName);
m_base->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
m_base->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
@@ -1993,7 +2008,7 @@ bool DomEnvironment::commitToBase(
if (m_lastValidBase) {
QMutexLocker lValid(
m_lastValidBase->mutex()); // be more careful about makeCopy calls with lock?
- m_base->m_semanticAnalysis = m_semanticAnalysis;
+ m_lastValidBase->m_semanticAnalysis = std::move(my_semanticAnalysis);
m_lastValidBase->m_globalScopeWithName.insert(my_globalScopeWithName);
m_lastValidBase->m_qmlDirectoryWithPath.insert(my_qmlDirectoryWithPath);
m_lastValidBase->m_qmldirFileWithPath.insert(my_qmldirFileWithPath);
@@ -2022,6 +2037,25 @@ bool DomEnvironment::commitToBase(
}
}
}
+
+ auto newBaseForPopulation =
+ m_lastValidBase ? m_lastValidBase->weak_from_this() : m_base->weak_from_this();
+ // adapt the factory to the use the base or valid environment for unpopulated files, instead of
+ // the current environment which will very probably be destroyed anytime soon
+ for (const auto &qmlFile : my_qmlFileWithPath) {
+ if (!qmlFile || !qmlFile->current)
+ continue;
+ QQmlJSScope::ConstPtr handle = qmlFile->current->handleForPopulation();
+ if (!handle)
+ continue;
+ auto oldFactory = handle.factory();
+ if (!oldFactory)
+ continue;
+
+ const QDeferredFactory<QQmlJSScope> newFactory(
+ oldFactory->importer(), oldFactory->filePath(), TypeReader{ newBaseForPopulation });
+ handle.resetFactory(newFactory);
+ }
return true;
}
@@ -2174,9 +2208,10 @@ void DomEnvironment::clearReferenceCache()
void DomEnvironment::populateFromQmlFile(MutableDomItem &&qmlFile)
{
if (std::shared_ptr<QmlFile> qmlFilePtr = qmlFile.ownerAs<QmlFile>()) {
- QQmlJSLogger logger; // TODO
- // the logger filename is used to populate the QQmlJSScope filepath.
- logger.setFileName(qmlFile.canonicalFilePath());
+ auto logger = std::make_shared<QQmlJSLogger>();
+ logger->setFileName(qmlFile.canonicalFilePath());
+ logger->setCode(qmlFilePtr->code());
+ logger->setSilent(true);
auto setupFile = [&qmlFilePtr, &qmlFile, this](auto &&visitor) {
Q_UNUSED(this); // note: integrity requires "this" to be in the capture list, while
@@ -2189,8 +2224,8 @@ void DomEnvironment::populateFromQmlFile(MutableDomItem &&qmlFile)
if (m_domCreationOptions.testFlag(DomCreationOption::WithSemanticAnalysis)) {
auto &analysis = semanticAnalysis();
auto scope = analysis.m_importer->importFile(qmlFile.canonicalFilePath());
- auto v = std::make_unique<QQmlDomAstCreatorWithQQmlJSScope>(scope, qmlFile, &logger,
- analysis.m_importer.get());
+ auto v = std::make_unique<QQmlDomAstCreatorWithQQmlJSScope>(
+ scope, qmlFile, logger.get(), analysis.m_importer.get());
v->enableLoadFileLazily(true);
v->enableScriptExpressions(m_domCreationOptions.testFlag(DomCreationOption::WithScriptExpressions));
@@ -2199,8 +2234,8 @@ void DomEnvironment::populateFromQmlFile(MutableDomItem &&qmlFile)
auto typeResolver =
std::make_shared<QQmlJSTypeResolver>(analysis.m_importer.get());
typeResolver->init(&v->scopeCreator(), nullptr);
- qmlFilePtr->setTypeResolverWithDependencies(typeResolver,
- { analysis.m_importer, analysis.m_mapper });
+ qmlFilePtr->setTypeResolverWithDependencies(
+ typeResolver, { analysis.m_importer, analysis.m_mapper, std::move(logger) });
} else {
auto v = std::make_unique<QQmlDomAstCreator>(qmlFile);
v->enableScriptExpressions(
diff --git a/src/qmldom/qqmldomtop_p.h b/src/qmldom/qqmldomtop_p.h
index 33a921af93..afdea6b311 100644
--- a/src/qmldom/qqmldomtop_p.h
+++ b/src/qmldom/qqmldomtop_p.h
@@ -721,6 +721,15 @@ class QMLDOM_EXPORT DomEnvironment final : public DomTop,
protected:
std::shared_ptr<OwningItem> doCopy(const DomItem &self) const override;
+private:
+ struct TypeReader
+ {
+ std::weak_ptr<DomEnvironment> m_env;
+
+ QList<QQmlJS::DiagnosticMessage>
+ operator()(QQmlJSImporter *importer, const QString &filePath,
+ const QSharedPointer<QQmlJSScope> &scopeToPopulate);
+ };
public:
enum class Option {
Default = 0x0,
diff --git a/src/qmlintegration/qqmlintegration.h b/src/qmlintegration/qqmlintegration.h
index f1a990a79c..0cea1bab30 100644
--- a/src/qmlintegration/qqmlintegration.h
+++ b/src/qmlintegration/qqmlintegration.h
@@ -192,4 +192,8 @@ QT_END_NAMESPACE
#define QML_CUSTOMPARSER \
Q_CLASSINFO("QML.HasCustomParser", "true")
+#define QML_USING(ORIGINAL) \
+ using QmlUsing ## ORIGINAL = ORIGINAL; \
+ Q_CLASSINFO("QML.Using", #ORIGINAL)
+
#endif
diff --git a/src/qmllocalstorage/CMakeLists.txt b/src/qmllocalstorage/CMakeLists.txt
index 8a67f14766..0517b2231a 100644
--- a/src/qmllocalstorage/CMakeLists.txt
+++ b/src/qmllocalstorage/CMakeLists.txt
@@ -15,5 +15,4 @@ qt_internal_add_qml_module(QmlLocalStorage
Qt::CorePrivate
Qt::QmlPrivate
Qt::Sql
- GENERATE_CPP_EXPORTS
)
diff --git a/src/qmlls/CMakeLists.txt b/src/qmlls/CMakeLists.txt
index 9476bb847e..b15fb396f8 100644
--- a/src/qmlls/CMakeLists.txt
+++ b/src/qmlls/CMakeLists.txt
@@ -33,6 +33,8 @@ qt_internal_add_module(QmlLSPrivate
qdochtmlparser_p.h qdochtmlparser.cpp
qqmlhighlightsupport_p.h qqmlhighlightsupport.cpp
qqmlsemantictokens_p.h qqmlsemantictokens.cpp
+ qqmllshelpplugininterface_p.h qqmllshelpplugininterface.cpp
+ qqmllshelputils_p.h qqmllshelputils.cpp
PUBLIC_LIBRARIES
Qt::LanguageServerPrivate
@@ -41,5 +43,4 @@ qt_internal_add_module(QmlLSPrivate
Qt::QmlCompilerPrivate
Qt::QmlToolingSettingsPrivate
Qt::LanguageServerPrivate
- GENERATE_CPP_EXPORTS
)
diff --git a/src/qmlls/qdochtmlparser.cpp b/src/qmlls/qdochtmlparser.cpp
index bba18facb5..bf885fb258 100644
--- a/src/qmlls/qdochtmlparser.cpp
+++ b/src/qmlls/qdochtmlparser.cpp
@@ -8,8 +8,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-namespace { //anonymous
-
// An emprical value to avoid too much content
static constexpr qsizetype firstIndexOfParagraphTag = 400;
@@ -20,7 +18,7 @@ static constexpr auto lengthOfStartParagraphTag = qsizetype(std::char_traits<cha
static constexpr auto lengthOfEndParagraphTag = qsizetype(std::char_traits<char>::length("</p>"));
static constexpr auto lengthOfPeriod = qsizetype(std::char_traits<char>::length("."));
-QString getContentsByMarks(const QString &html, QString startMark, QString endMark)
+static QString getContentsByMarks(const QString &html, QString startMark, QString endMark)
{
startMark.prepend("$$$"_L1);
endMark.prepend("<!-- @@@"_L1);
@@ -41,7 +39,7 @@ QString getContentsByMarks(const QString &html, QString startMark, QString endMa
}
-void stripAllHtml(QString *html)
+static void stripAllHtml(QString *html)
{
Q_ASSERT(html);
html->remove(QRegularExpression("<.*?>"_L1));
@@ -51,7 +49,7 @@ void stripAllHtml(QString *html)
\brief Process the string obtained from start mark to end mark.
This is duplicated from QtC's Utils::HtmlExtractor, modified on top of it.
*/
-void processOutput(QString *html)
+static void processOutput(QString *html)
{
Q_ASSERT(html);
if (html->isEmpty())
@@ -95,43 +93,30 @@ void processOutput(QString *html)
}
}
-}
-
-QDocHtmlExtractor::QDocHtmlExtractor(const QString &code) : m_code{ code }
+class ExtractQmlType : public HtmlExtractor
{
-}
+public:
+ QString extract(const QString &code, const QString &keyword, ExtractionMode mode) override;
+};
-QString QDocHtmlExtractor::extract(const QDocHtmlExtractor::Element &element, ExtractionMode mode)
+class ExtractQmlProperty : public HtmlExtractor
{
- QString result;
- switch (element.type) {
- case ElementType::QmlType:
- result = parseForQmlType(element.name, mode);
- break;
+public:
+ QString extract(const QString &code, const QString &keyword, ExtractionMode mode) override;
+};
- case ElementType::QmlProperty:
- result = parseForQmlProperty(element.name, mode);
- break;
- case ElementType::QmlMethod:
- case ElementType::QmlSignal:
- result = parseForQmlMethodOrSignal(element.name, mode);
- break;
- default:
- return {};
- }
-
- stripAllHtml(&result);
-
- // Also remove leading and trailing whitespaces
- return result.trimmed();
-}
+class ExtractQmlMethodOrSignal : public HtmlExtractor
+{
+public:
+ QString extract(const QString &code, const QString &keyword, ExtractionMode mode) override;
+};
-QString QDocHtmlExtractor::parseForQmlType(const QString &element, ExtractionMode mode)
+QString ExtractQmlType::extract(const QString &code, const QString &element, ExtractionMode mode)
{
QString result;
// Get brief description
- if (mode == QDocHtmlExtractor::ExtractionMode::Simplified) {
- result = getContentsByMarks(m_code, element + "-brief"_L1 , element);
+ if (mode == ExtractionMode::Simplified) {
+ result = getContentsByMarks(code, element + "-brief"_L1 , element);
// Remove More...
if (!result.isEmpty()) {
const auto tailToRemove = "More..."_L1;
@@ -140,7 +125,7 @@ QString QDocHtmlExtractor::parseForQmlType(const QString &element, ExtractionMod
result.remove(lastIndex, tailToRemove.length());
}
} else {
- result = getContentsByMarks(m_code, element + "-description"_L1, element);
+ result = getContentsByMarks(code, element + "-description"_L1, element);
// Remove header
if (!result.isEmpty()) {
const auto headerToRemove = "Detailed Description"_L1;
@@ -150,25 +135,26 @@ QString QDocHtmlExtractor::parseForQmlType(const QString &element, ExtractionMod
}
}
- return result;
+ stripAllHtml(&result);
+ return result.trimmed();
}
-QString QDocHtmlExtractor::parseForQmlProperty(const QString &element, ExtractionMode mode)
+QString ExtractQmlProperty::extract(const QString &code, const QString &keyword, ExtractionMode mode)
{
// Qt 5.15 way of finding properties in doc
- QString startMark = QString::fromLatin1("<a name=\"%1-prop\">").arg(element);
- qsizetype startIndex = m_code.indexOf(startMark);
+ QString startMark = QString::fromLatin1("<a name=\"%1-prop\">").arg(keyword);
+ qsizetype startIndex = code.indexOf(startMark);
if (startIndex == -1) {
// if not found, try Qt6
startMark = QString::fromLatin1(
"<td class=\"tblQmlPropNode\"><p>\n<span class=\"name\">%1</span>")
- .arg(element);
- startIndex = m_code.indexOf(startMark);
+ .arg(keyword);
+ startIndex = code.indexOf(startMark);
if (startIndex == -1)
return {};
}
- QString contents = m_code.mid(startIndex + startMark.size());
+ QString contents = code.mid(startIndex + startMark.size());
startIndex = contents.indexOf(QLatin1String("<div class=\"qmldoc\"><p>"));
if (startIndex == -1)
return {};
@@ -176,39 +162,66 @@ QString QDocHtmlExtractor::parseForQmlProperty(const QString &element, Extractio
contents = contents.mid(startIndex);
if (mode == ExtractionMode::Simplified)
processOutput(&contents);
- return contents;
+ stripAllHtml(&contents);
+ return contents.trimmed();
}
-QString QDocHtmlExtractor::parseForQmlMethodOrSignal(const QString &functionName, ExtractionMode mode)
+QString ExtractQmlMethodOrSignal::extract(const QString &code, const QString &keyword, ExtractionMode mode)
{
// the case with <!-- $$$childAt[overload1]$$$childAtrealreal -->
- QString mark = QString::fromLatin1("$$$%1[overload1]$$$%1").arg(functionName);
- qsizetype startIndex = m_code.indexOf(mark);
+ QString mark = QString::fromLatin1("$$$%1[overload1]$$$%1").arg(keyword);
+ qsizetype startIndex = code.indexOf(mark);
if (startIndex != -1) {
- startIndex = m_code.indexOf("-->"_L1, startIndex + mark.length());
+ startIndex = code.indexOf("-->"_L1, startIndex + mark.length());
if (startIndex == -1)
return {};
} else {
// it could be part of the method list
mark = QString::fromLatin1("<span class=\"name\">%1</span>")
- .arg(functionName);
- startIndex = m_code.indexOf(mark);
+ .arg(keyword);
+ startIndex = code.indexOf(mark);
if (startIndex != -1)
startIndex += mark.length();
else
return {};
}
- startIndex = m_code.indexOf(QLatin1String("<div class=\"qmldoc\"><p>"), startIndex);
+ startIndex = code.indexOf(QLatin1String("<div class=\"qmldoc\"><p>"), startIndex);
if (startIndex == -1)
return {};
QString endMark = QString::fromLatin1("<!-- @@@");
- qsizetype endIndex = m_code.indexOf(endMark, startIndex);
- QString contents = m_code.mid(startIndex, endIndex);
+ qsizetype endIndex = code.indexOf(endMark, startIndex);
+ QString contents = code.mid(startIndex, endIndex);
if (mode == ExtractionMode::Simplified)
processOutput(&contents);
- return contents;
+ stripAllHtml(&contents);
+ return contents.trimmed();
+}
+
+ExtractDocumentation::ExtractDocumentation(QQmlJS::Dom::DomType domType)
+{
+ using namespace QQmlJS::Dom;
+ switch (domType) {
+ case DomType::QmlObject:
+ m_extractor = std::make_unique<ExtractQmlType>();
+ break;
+ case DomType::Binding:
+ case DomType::PropertyDefinition:
+ m_extractor = std::make_unique<ExtractQmlProperty>();
+ break;
+ case DomType::MethodInfo:
+ m_extractor = std::make_unique<ExtractQmlMethodOrSignal>();
+ break;
+ default:
+ break;
+ }
+}
+
+QString ExtractDocumentation::execute(const QString &code, const QString &keyword, HtmlExtractor::ExtractionMode mode)
+{
+ Q_ASSERT(m_extractor);
+ return m_extractor->extract(code, keyword, mode);
}
QT_END_NAMESPACE
diff --git a/src/qmlls/qdochtmlparser_p.h b/src/qmlls/qdochtmlparser_p.h
index f66fb0e56b..d09f2f882e 100644
--- a/src/qmlls/qdochtmlparser_p.h
+++ b/src/qmlls/qdochtmlparser_p.h
@@ -15,35 +15,27 @@
// We mean it.
//
+#include <QtQmlDom/private/qqmldomtop_p.h>
#include <QString>
QT_BEGIN_NAMESPACE
-class QDocHtmlExtractor
+class HtmlExtractor
{
public:
enum class ExtractionMode : char { Simplified, Extended };
- enum class ElementType : char {
- QmlType,
- QmlProperty,
- QmlMethod,
- QmlSignal
- };
- struct Element {
- QString name;
- ElementType type;
- };
-
- QDocHtmlExtractor(const QString &code);
- QString extract(const Element &element, ExtractionMode extractionMode);
+ virtual QString extract(const QString &code, const QString &keyword, ExtractionMode mode) = 0;
+ virtual ~HtmlExtractor() = default;
+};
+class ExtractDocumentation
+{
+public:
+ ExtractDocumentation(QQmlJS::Dom::DomType domType);
+ QString execute(const QString &code, const QString &keyword, HtmlExtractor::ExtractionMode mode);
private:
- QString parseForQmlType(const QString &element, ExtractionMode mode);
- QString parseForQmlProperty(const QString &element, ExtractionMode mode = ExtractionMode::Simplified);
- QString parseForQmlMethodOrSignal(const QString &functionName, ExtractionMode mode);
-
- const QString &m_code;
+ std::unique_ptr<HtmlExtractor> m_extractor;
};
QT_END_NAMESPACE
diff --git a/src/qmlls/qlanguageserver.cpp b/src/qmlls/qlanguageserver.cpp
index b65873ef5d..4babb3ebba 100644
--- a/src/qmlls/qlanguageserver.cpp
+++ b/src/qmlls/qlanguageserver.cpp
@@ -8,11 +8,11 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lspServerLog, "qt.languageserver.server")
+
using namespace QLspSpecification;
using namespace Qt::StringLiterals;
-Q_LOGGING_CATEGORY(lspServerLog, "qt.languageserver.server")
-
QLanguageServerPrivate::QLanguageServerPrivate(const QJsonRpcTransport::DataHandler &h)
: protocol(h)
{
@@ -226,9 +226,15 @@ const QLspSpecification::InitializeResult &QLanguageServer::serverInfo() const
return d->serverInfo;
}
-void QLanguageServer::receiveData(const QByteArray &d)
+void QLanguageServer::receiveData(const QByteArray &data, bool isEndOfMessage)
{
- protocol()->receiveData(d);
+ if (!data.isEmpty())
+ protocol()->receiveData(data);
+
+ const Q_D(QLanguageServer);
+ // read next message if not shutting down
+ if (isEndOfMessage && d->runStatus != RunStatus::Stopped)
+ emit readNextMessage();
}
void QLanguageServer::registerHandlers(QLanguageServerProtocol *protocol)
diff --git a/src/qmlls/qlanguageserver_p.h b/src/qmlls/qlanguageserver_p.h
index 019a059823..53118c00c8 100644
--- a/src/qmlls/qlanguageserver_p.h
+++ b/src/qmlls/qlanguageserver_p.h
@@ -73,13 +73,14 @@ public:
const QLspSpecification::InitializeResult &serverInfo() const;
public Q_SLOTS:
- void receiveData(const QByteArray &d);
+ void receiveData(const QByteArray &d, bool isEndOfMessage);
Q_SIGNALS:
void runStatusChanged(RunStatus);
void clientInitialized(QLanguageServer *server);
void shutdown();
void exit();
void lifecycleError();
+ void readNextMessage();
private:
void registerMethods(QJsonRpc::TypedRpc &typedRpc);
diff --git a/src/qmlls/qqmlbasemodule_p.h b/src/qmlls/qqmlbasemodule_p.h
index 47596914cb..294b38fa40 100644
--- a/src/qmlls/qqmlbasemodule_p.h
+++ b/src/qmlls/qqmlbasemodule_p.h
@@ -55,7 +55,7 @@ struct ResponseScopeGuard
{
Q_DISABLE_COPY_MOVE(ResponseScopeGuard)
- std::variant<Result *, QQmlLSUtilsErrorMessage> m_response;
+ std::variant<Result *, QQmlLSUtils::ErrorMessage> m_response;
ResponseCallback &m_callback;
ResponseScopeGuard(Result &results, ResponseCallback &callback)
@@ -64,15 +64,15 @@ struct ResponseScopeGuard
}
// note: discards the current result or error message, if there is any
- void setError(const QQmlLSUtilsErrorMessage &error) { m_response = error; }
+ void setError(const QQmlLSUtils::ErrorMessage &error) { m_response = error; }
template<typename... T>
bool setErrorFrom(const std::variant<T...> &variant)
{
- static_assert(std::disjunction_v<std::is_same<T, QQmlLSUtilsErrorMessage>...>,
+ static_assert(std::disjunction_v<std::is_same<T, QQmlLSUtils::ErrorMessage>...>,
"ResponseScopeGuard::setErrorFrom was passed a variant that never contains"
" an error message.");
- if (auto x = std::get_if<QQmlLSUtilsErrorMessage>(&variant)) {
+ if (auto x = std::get_if<QQmlLSUtils::ErrorMessage>(&variant)) {
setError(*x);
return true;
}
@@ -89,7 +89,7 @@ struct ResponseScopeGuard
// xxx was not an error, continue
\endcode
*/
- bool setErrorFrom(const std::optional<QQmlLSUtilsErrorMessage> &error)
+ bool setErrorFrom(const std::optional<QQmlLSUtils::ErrorMessage> &error)
{
if (error) {
setError(*error);
@@ -101,7 +101,7 @@ struct ResponseScopeGuard
~ResponseScopeGuard()
{
std::visit(qOverloadedVisitor{ [this](Result *result) { m_callback.sendResponse(*result); },
- [this](const QQmlLSUtilsErrorMessage &error) {
+ [this](const QQmlLSUtils::ErrorMessage &error) {
m_callback.sendErrorResponse(error.code,
error.message.toUtf8());
} },
@@ -125,7 +125,7 @@ struct QQmlBaseModule : public QLanguageServerModule
decltype(auto) getRequestHandler();
// processes a request in a different thread.
virtual void process(RequestPointerArgument toBeProcessed) = 0;
- std::variant<QList<QQmlLSUtilsItemLocation>, QQmlLSUtilsErrorMessage>
+ std::variant<QList<QQmlLSUtils::ItemLocation>, QQmlLSUtils::ErrorMessage>
itemsForRequest(const RequestPointer &request);
public Q_SLOTS:
@@ -228,7 +228,7 @@ void QQmlBaseModule<RequestType>::updatedSnapshot(const QByteArray &url)
}
template<typename RequestType>
-std::variant<QList<QQmlLSUtilsItemLocation>, QQmlLSUtilsErrorMessage>
+std::variant<QList<QQmlLSUtils::ItemLocation>, QQmlLSUtils::ErrorMessage>
QQmlBaseModule<RequestType>::itemsForRequest(const RequestPointer &request)
{
@@ -236,9 +236,9 @@ QQmlBaseModule<RequestType>::itemsForRequest(const RequestPointer &request)
QQmlLSUtils::lspUriToQmlUrl(request->m_parameters.textDocument.uri));
if (!doc.snapshot.validDocVersion || doc.snapshot.validDocVersion != doc.snapshot.docVersion) {
- return QQmlLSUtilsErrorMessage{ 0,
- u"Cannot proceed: current QML document is invalid! Fix"
- u" all the errors in your QML code and try again."_s };
+ return QQmlLSUtils::ErrorMessage{ 0,
+ u"Cannot proceed: current QML document is invalid! Fix"
+ u" all the errors in your QML code and try again."_s };
}
QQmlJS::Dom::DomItem file = doc.snapshot.validDoc.fileObject(QQmlJS::Dom::GoTo::MostLikely);
@@ -246,7 +246,7 @@ QQmlBaseModule<RequestType>::itemsForRequest(const RequestPointer &request)
if (auto envPtr = file.environment().ownerAs<QQmlJS::Dom::DomEnvironment>())
envPtr->clearReferenceCache();
if (!file) {
- return QQmlLSUtilsErrorMessage{
+ return QQmlLSUtils::ErrorMessage{
0,
u"Could not find file %1 in project."_s.arg(doc.snapshot.doc.toString()),
};
@@ -256,7 +256,7 @@ QQmlBaseModule<RequestType>::itemsForRequest(const RequestPointer &request)
request->m_parameters.position.character);
if (itemsFound.isEmpty()) {
- return QQmlLSUtilsErrorMessage{
+ return QQmlLSUtils::ErrorMessage{
0,
u"Could not find any items at given text location."_s,
};
diff --git a/src/qmlls/qqmlcodemodel.cpp b/src/qmlls/qqmlcodemodel.cpp
index 85d08f89b6..fe6c220f3b 100644
--- a/src/qmlls/qqmlcodemodel.cpp
+++ b/src/qmlls/qqmlcodemodel.cpp
@@ -21,7 +21,7 @@ QT_BEGIN_NAMESPACE
namespace QmlLsp {
-Q_LOGGING_CATEGORY(codeModelLog, "qt.languageserver.codemodel")
+Q_STATIC_LOGGING_CATEGORY(codeModelLog, "qt.languageserver.codemodel")
using namespace QQmlJS::Dom;
using namespace Qt::StringLiterals;
@@ -609,6 +609,18 @@ void QQmlCodeModel::newDocForOpenFile(const QByteArray &url, int version, const
if (std::shared_ptr<DomEnvironment> newCurrentPtr = newCurrent.ownerAs<DomEnvironment>()) {
newCurrentPtr->setLoadPaths(loadPaths);
}
+
+ // if the documentation root path is not set through the commandline,
+ // try to set it from the settings file (.qmlls.ini file)
+ if (m_documentationRootPath.isEmpty()) {
+ const QString path = url2Path(url);
+ if (m_settings && m_settings->search(path)) {
+ const QString docDir = QStringLiteral(u"docDir");
+ if (m_settings->isSet(docDir))
+ setDocumentationRootPath(m_settings->value(docDir).toString());
+ }
+ }
+
Path p;
auto newCurrentPtr = newCurrent.ownerAs<DomEnvironment>();
newCurrentPtr->loadFile(FileToLoad::fromMemory(newCurrentPtr, fPath, docText),
@@ -808,6 +820,15 @@ QStringList QQmlCodeModel::buildPathsForFileUrl(const QByteArray &url)
return res;
}
+void QQmlCodeModel::setDocumentationRootPath(const QString &path)
+{
+ QMutexLocker l(&m_mutex);
+ if (m_documentationRootPath != path) {
+ m_documentationRootPath = path;
+ emit documentationRootPathChanged(path);
+ }
+}
+
void QQmlCodeModel::setBuildPathsForRootUrl(QByteArray url, const QStringList &paths)
{
QMutexLocker l(&m_mutex);
diff --git a/src/qmlls/qqmlcodemodel_p.h b/src/qmlls/qqmlcodemodel_p.h
index 0009a7e48b..38aec2c244 100644
--- a/src/qmlls/qqmlcodemodel_p.h
+++ b/src/qmlls/qqmlcodemodel_p.h
@@ -86,8 +86,8 @@ public:
explicit QQmlCodeModel(QObject *parent = nullptr, QQmlToolingSettings *settings = nullptr);
~QQmlCodeModel();
- QQmlJS::Dom::DomItem currentEnv();
- QQmlJS::Dom::DomItem validEnv();
+ QQmlJS::Dom::DomItem currentEnv() const { return m_currentEnv; };
+ QQmlJS::Dom::DomItem validEnv() const { return m_validEnv; };
OpenDocumentSnapshot snapshotByUrl(const QByteArray &url);
OpenDocument openDocumentByUrl(const QByteArray &url);
@@ -110,7 +110,7 @@ public:
QStringList importPaths() const { return m_importPaths; };
void setImportPaths(const QStringList &paths) { m_importPaths = paths; };
void removeRootUrls(const QList<QByteArray> &urls);
- QQmlToolingSettings *settings();
+ QQmlToolingSettings *settings() const { return m_settings; }
QStringList findFilePathsFromFileNames(const QStringList &fileNames) const;
static QStringList fileNamesToWatch(const QQmlJS::Dom::DomItem &qmlFile);
void disableCMakeCalls();
@@ -118,9 +118,13 @@ public:
RegisteredSemanticTokens &registeredTokens();
const RegisteredSemanticTokens &registeredTokens() const;
+ QString documentationRootPath() const { return m_documentationRootPath; }
+ void setDocumentationRootPath(const QString &path);
Q_SIGNALS:
void updatedSnapshot(const QByteArray &url);
+ void documentationRootPathChanged(const QString &path);
+
private:
void indexDirectory(const QString &path, int depthLeft);
int indexEvalProgress() const; // to be called in the mutex
@@ -164,6 +168,7 @@ private:
bool m_rebuildRequired = true; // always trigger a rebuild on start
CMakeStatus m_cmakeStatus = RequiresInitialization;
RegisteredSemanticTokens m_tokens;
+ QString m_documentationRootPath;
private slots:
void onCppFileChanged(const QString &);
};
diff --git a/src/qmlls/qqmlcompletionsupport.cpp b/src/qmlls/qqmlcompletionsupport.cpp
index 371a5eb447..632a5e902a 100644
--- a/src/qmlls/qqmlcompletionsupport.cpp
+++ b/src/qmlls/qqmlcompletionsupport.cpp
@@ -169,6 +169,11 @@ QList<CompletionItem> CompletionRequest::completions(QmlLsp::OpenDocumentSnapsho
auto itemsFound = QQmlLSUtils::itemsFromTextLocation(file, m_parameters.position.line,
m_parameters.position.character
- ctx.filterChars().size());
+ if (itemsFound.isEmpty()) {
+ qCDebug(QQmlLSCompletionLog) << "No items found for completions at" << urlAndPos();
+ return {};
+ }
+
if (itemsFound.size() > 1) {
QStringList paths;
for (auto &it : itemsFound)
@@ -176,11 +181,7 @@ QList<CompletionItem> CompletionRequest::completions(QmlLsp::OpenDocumentSnapsho
qCWarning(QQmlLSCompletionLog) << "Multiple elements of " << urlAndPos()
<< " at the same depth:" << paths << "(using first)";
}
- DomItem currentItem;
- if (!itemsFound.isEmpty())
- currentItem = itemsFound.first().domItem;
- else
- qCDebug(QQmlLSCompletionLog) << "No items found for completions at" << urlAndPos();
+ const DomItem currentItem = itemsFound.first().domItem;
qCDebug(QQmlLSCompletionLog) << "Completion at " << urlAndPos() << " "
<< m_parameters.position.line << ":"
<< m_parameters.position.character << "offset:" << pos
diff --git a/src/qmlls/qqmlcompletionsupport_p.h b/src/qmlls/qqmlcompletionsupport_p.h
index fa0c1ca51a..3d7fa03d94 100644
--- a/src/qmlls/qqmlcompletionsupport_p.h
+++ b/src/qmlls/qqmlcompletionsupport_p.h
@@ -39,7 +39,8 @@ struct CompletionRequest
QString urlAndPos() const;
QList<QLspSpecification::CompletionItem>
completions(QmlLsp::OpenDocumentSnapshot &doc, const QQmlLSCompletion &completionEngine) const;
- DomItem patchInvalidFileForParser(const DomItem& file, qsizetype position) const;
+ QQmlJS::Dom::DomItem patchInvalidFileForParser(const QQmlJS::Dom::DomItem &file,
+ qsizetype position) const;
};
class QmlCompletionSupport : public QQmlBaseModule<CompletionRequest>
diff --git a/src/qmlls/qqmlfindusagessupport.cpp b/src/qmlls/qqmlfindusagessupport.cpp
index 8a3dca7e3a..dc407f71bc 100644
--- a/src/qmlls/qqmlfindusagessupport.cpp
+++ b/src/qmlls/qqmlfindusagessupport.cpp
@@ -44,7 +44,8 @@ void QQmlFindUsagesSupport::process(QQmlFindUsagesSupport::RequestPointerArgumen
if (guard.setErrorFrom(itemsFound))
return;
- QQmlLSUtilsItemLocation &front = std::get<QList<QQmlLSUtilsItemLocation>>(itemsFound).front();
+ QQmlLSUtils::ItemLocation &front =
+ std::get<QList<QQmlLSUtils::ItemLocation>>(itemsFound).front();
auto usages = QQmlLSUtils::findUsagesOf(front.domItem);
@@ -52,7 +53,8 @@ void QQmlFindUsagesSupport::process(QQmlFindUsagesSupport::RequestPointerArgumen
QHash<QString, QString> codeCache;
- for (const auto &usage : usages) {
+ // note: ignore usages in filenames here as that is not supported by the protocol.
+ for (const auto &usage : usages.usagesInFile()) {
QLspSpecification::Location location;
location.uri = QUrl::fromLocalFile(usage.filename).toEncoded();
diff --git a/src/qmlls/qqmlformatting.cpp b/src/qmlls/qqmlformatting.cpp
index 82313f1c65..cf0cdf5147 100644
--- a/src/qmlls/qqmlformatting.cpp
+++ b/src/qmlls/qqmlformatting.cpp
@@ -47,12 +47,12 @@ void QQmlDocumentFormatting::process(RequestPointerArgument request)
DomItem file = doc.snapshot.doc.fileObject(GoTo::MostLikely);
if (!file) {
- guard.setError(QQmlLSUtilsErrorMessage{
+ guard.setError(QQmlLSUtils::ErrorMessage{
0, u"Could not find the file %1"_s.arg(doc.snapshot.doc.canonicalFilePath()) });
return;
}
if (!file.field(Fields::isValid).value().toBool(false)) {
- guard.setError(QQmlLSUtilsErrorMessage{ 0, u"Cannot format invalid documents!"_s });
+ guard.setError(QQmlLSUtils::ErrorMessage{ 0, u"Cannot format invalid documents!"_s });
return;
}
if (auto envPtr = file.environment().ownerAs<DomEnvironment>())
@@ -66,7 +66,7 @@ void QQmlDocumentFormatting::process(RequestPointerArgument request)
return true;
},
true);
- guard.setError(QQmlLSUtilsErrorMessage{
+ guard.setError(QQmlLSUtils::ErrorMessage{
0, u"Failed to parse %1"_s.arg(file.canonicalFilePath()) });
return;
}
diff --git a/src/qmlls/qqmlformatting_p.h b/src/qmlls/qqmlformatting_p.h
index 465a32e31d..19fc30683e 100644
--- a/src/qmlls/qqmlformatting_p.h
+++ b/src/qmlls/qqmlformatting_p.h
@@ -21,6 +21,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(formatLog)
+
struct DocumentFormattingRequest
: public BaseRequest<QLspSpecification::DocumentFormattingParams,
QLspSpecification::Responses::DocumentFormattingResponseType>
diff --git a/src/qmlls/qqmlgotodefinitionsupport.cpp b/src/qmlls/qqmlgotodefinitionsupport.cpp
index 0a5579a057..366fbe7d09 100644
--- a/src/qmlls/qqmlgotodefinitionsupport.cpp
+++ b/src/qmlls/qqmlgotodefinitionsupport.cpp
@@ -47,7 +47,7 @@ void QmlGoToDefinitionSupport::process(RequestPointerArgument request)
if (guard.setErrorFrom(itemsFound))
return;
- QQmlLSUtilsItemLocation &front = std::get<QList<QQmlLSUtilsItemLocation>>(itemsFound).front();
+ auto &front = std::get<QList<QQmlLSUtils::ItemLocation>>(itemsFound).front();
auto location = QQmlLSUtils::findDefinitionOf(front.domItem);
if (!location)
diff --git a/src/qmlls/qqmlgototypedefinitionsupport.cpp b/src/qmlls/qqmlgototypedefinitionsupport.cpp
index d8a0277a62..b29cf3b833 100644
--- a/src/qmlls/qqmlgototypedefinitionsupport.cpp
+++ b/src/qmlls/qqmlgototypedefinitionsupport.cpp
@@ -46,7 +46,7 @@ void QmlGoToTypeDefinitionSupport::process(RequestPointerArgument request)
if (guard.setErrorFrom(itemsFound))
return;
- QQmlLSUtilsItemLocation &front = std::get<QList<QQmlLSUtilsItemLocation>>(itemsFound).front();
+ auto &front = std::get<QList<QQmlLSUtils::ItemLocation>>(itemsFound).front();
auto base = QQmlLSUtils::findTypeDefinitionOf(front.domItem);
diff --git a/src/qmlls/qqmlhighlightsupport.cpp b/src/qmlls/qqmlhighlightsupport.cpp
index 55002804a0..b3892fbb38 100644
--- a/src/qmlls/qqmlhighlightsupport.cpp
+++ b/src/qmlls/qqmlhighlightsupport.cpp
@@ -54,14 +54,13 @@ SemanticTokenFullHandler::SemanticTokenFullHandler(QmlLsp::QQmlCodeModel *codeMo
void SemanticTokenFullHandler::process(
QQmlBaseModule<SemanticTokensRequest>::RequestPointerArgument request)
{
- Responses::SemanticTokensResultType result;
- ResponseScopeGuard guard(result, request->m_response);
-
if (!request) {
qCWarning(semanticTokens) << "No semantic token request is available!";
return;
}
+ Responses::SemanticTokensResultType result;
+ ResponseScopeGuard guard(result, request->m_response);
const auto doc = m_codeModel->openDocumentByUrl(
QQmlLSUtils::lspUriToQmlUrl(request->m_parameters.textDocument.uri));
DomItem file = doc.snapshot.doc.fileObject(GoTo::MostLikely);
@@ -97,13 +96,13 @@ SemanticTokenDeltaHandler::SemanticTokenDeltaHandler(QmlLsp::QQmlCodeModel *code
void SemanticTokenDeltaHandler::process(
QQmlBaseModule<SemanticTokensDeltaRequest>::RequestPointerArgument request)
{
- Responses::SemanticTokensDeltaResultType result;
- ResponseScopeGuard guard(result, request->m_response);
-
if (!request) {
qCWarning(semanticTokens) << "No semantic token request is available!";
return;
}
+
+ Responses::SemanticTokensDeltaResultType result;
+ ResponseScopeGuard guard(result, request->m_response);
const auto doc = m_codeModel->openDocumentByUrl(
QQmlLSUtils::lspUriToQmlUrl(request->m_parameters.textDocument.uri));
DomItem file = doc.snapshot.validDoc.fileObject(GoTo::MostLikely);
@@ -116,15 +115,16 @@ void SemanticTokenDeltaHandler::process(
// Return full token list if result ids not align
// otherwise compute the delta.
if (lastResultId == request->m_parameters.previousResultId) {
- auto &&oldEncoded = registeredTokens.lastTokens;
- QList<SemanticTokensEdit> edits = HighlightingUtils::computeDiff(oldEncoded, newEncoded);
- result = QLspSpecification::SemanticTokensDelta{ registeredTokens.resultId, edits };
+ result = QLspSpecification::SemanticTokensDelta {
+ registeredTokens.resultId,
+ HighlightingUtils::computeDiff(registeredTokens.lastTokens, newEncoded)
+ };
} else if (!newEncoded.isEmpty()){
result = QLspSpecification::SemanticTokens{ registeredTokens.resultId, newEncoded };
} else {
result = nullptr;
}
- registeredTokens.lastTokens = newEncoded;
+ registeredTokens.lastTokens = std::move(newEncoded);
}
void SemanticTokenDeltaHandler::registerHandlers(QLanguageServer *, QLanguageServerProtocol *protocol)
@@ -146,20 +146,20 @@ SemanticTokenRangeHandler::SemanticTokenRangeHandler(QmlLsp::QQmlCodeModel *code
void SemanticTokenRangeHandler::process(
QQmlBaseModule<SemanticTokensRangeRequest>::RequestPointerArgument request)
{
- Responses::SemanticTokensRangeResultType result;
- ResponseScopeGuard guard(result, request->m_response);
-
if (!request) {
qCWarning(semanticTokens) << "No semantic token request is available!";
return;
}
+
+ Responses::SemanticTokensRangeResultType result;
+ ResponseScopeGuard guard(result, request->m_response);
const auto doc = m_codeModel->openDocumentByUrl(
QQmlLSUtils::lspUriToQmlUrl(request->m_parameters.textDocument.uri));
DomItem file = doc.snapshot.doc.fileObject(GoTo::MostLikely);
const auto qmlFile = file.as<QmlFile>();
if (!qmlFile)
return;
- const auto code = qmlFile->code();
+ const QString &code = qmlFile->code();
const auto range = request->m_parameters.range;
int startOffset = int(QQmlLSUtils::textOffsetFrom(code, range.start.line, range.end.character));
int endOffset = int(QQmlLSUtils::textOffsetFrom(code, range.end.line, range.end.character));
@@ -168,7 +168,7 @@ void SemanticTokenRangeHandler::process(
auto &registeredTokens = m_codeModel->registeredTokens();
if (!encoded.isEmpty()) {
HighlightingUtils::updateResultID(registeredTokens.resultId);
- result = SemanticTokens{ registeredTokens.resultId, encoded };
+ result = SemanticTokens{ registeredTokens.resultId, std::move(encoded) };
} else {
result = nullptr;
}
diff --git a/src/qmlls/qqmlhover.cpp b/src/qmlls/qqmlhover.cpp
index 4f604558a3..d2acd7b5d9 100644
--- a/src/qmlls/qqmlhover.cpp
+++ b/src/qmlls/qqmlhover.cpp
@@ -1,17 +1,27 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <qqmlhover_p.h>
+#include "qqmlhover_p.h"
+#include <QtQmlLS/private/qqmllshelputils_p.h>
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(hoverLog, "qt.languageserver.hover")
QQmlHover::QQmlHover(QmlLsp::QQmlCodeModel *codeModel)
- : QQmlBaseModule(codeModel)
+ : QQmlBaseModule(codeModel), m_helpManager(std::make_unique<HelpManager>())
{
+ // if set thorugh the commandline
+ if (!codeModel->documentationRootPath().isEmpty())
+ m_helpManager->setDocumentationRootPath(codeModel->documentationRootPath());
+
+ connect(codeModel, &QmlLsp::QQmlCodeModel::documentationRootPathChanged, this, [this](const QString &path) {
+ m_helpManager->setDocumentationRootPath(path);
+ });
}
+QQmlHover::~QQmlHover() = default;
+
QString QQmlHover::name() const
{
return u"QQmlHover"_s;
@@ -31,51 +41,42 @@ void QQmlHover::setupCapabilities(
void QQmlHover::process(RequestPointerArgument request)
{
+ if (!m_helpManager) {
+ qCWarning(hoverLog)
+ << "No help manager is available, documentation hints will not function!";
+ return;
+ }
using namespace QQmlJS::Dom;
QLspSpecification::Hover result;
ResponseScopeGuard guard(result, request->m_response);
-
if (!request) {
qCWarning(hoverLog) << "No hover information is available!";
return;
}
-
const auto textDocument = request->m_parameters.textDocument;
- const auto [hoveredLine, hoveredCharacter] = request->m_parameters.position;
- qCDebug(hoverLog) << QStringLiteral("Hovered (line, col): (%1,%2)").arg(hoveredLine).arg(hoveredCharacter);
-
- const auto doc = m_codeModel->openDocumentByUrl(
- QQmlLSUtils::lspUriToQmlUrl(textDocument.uri));
-
+ const auto position = request->m_parameters.position;
+ const auto doc = m_codeModel->openDocumentByUrl(QQmlLSUtils::lspUriToQmlUrl(textDocument.uri));
DomItem file = doc.snapshot.doc.fileObject(GoTo::MostLikely);
if (!file) {
- guard.setError(QQmlLSUtilsErrorMessage{
+ guard.setError(QQmlLSUtils::ErrorMessage{
0, u"Could not find the file %1"_s.arg(doc.snapshot.doc.canonicalFilePath()) });
return;
}
- // TODO: Fetch the actual documentation or other possible infos to be shown when hovered.
- // Early return if hovered element is not identifier kind (for example, don't perform anything on paranthesis)
-
- const auto documentation = QQmlLSUtils::getDocumentationFromLocation(
- file, { hoveredLine + 1, hoveredCharacter + 1 });
- if (documentation.isEmpty()) {
+ const auto documentation = m_helpManager->documentationForItem(file, position);
+ if (!documentation.has_value()) {
qCDebug(hoverLog)
<< QStringLiteral(
"No documentation hints found for the item at (line, col): (%1,%2)")
- .arg(hoveredLine)
- .arg(hoveredCharacter);
+ .arg(position.line)
+ .arg(position.character);
return;
}
-
QLspSpecification::MarkupContent content;
-
- // TODO: This should eventually be a Markdown kind.
- // We will do post-formatting what we fetch from documentation.
- content.kind = QLspSpecification::MarkupKind::PlainText;
- content.value = documentation;
-
- result.contents = content;
+ // TODO: We need to do post-formatting what we fetch from documentation.
+ content.kind = QLspSpecification::MarkupKind::Markdown;
+ content.value = documentation.value();
+ result.contents = std::move(content);
}
QT_END_NAMESPACE
diff --git a/src/qmlls/qqmlhover_p.h b/src/qmlls/qqmlhover_p.h
index 6d3fa59c62..ba964adc8b 100644
--- a/src/qmlls/qqmlhover_p.h
+++ b/src/qmlls/qqmlhover_p.h
@@ -26,17 +26,21 @@ struct HoverRequest
QLspSpecification::Responses::HoverResponseType>
{
};
-
+class HelpManager;
class QQmlHover : public QQmlBaseModule<HoverRequest>
{
Q_OBJECT
public:
QQmlHover(QmlLsp::QQmlCodeModel *codeModel);
+ ~QQmlHover() override;
QString name() const override;
void registerHandlers(QLanguageServer *server, QLanguageServerProtocol *protocol) override;
void setupCapabilities(const QLspSpecification::InitializeParams &clientInfo,
QLspSpecification::InitializeResult &) override;
void process(RequestPointerArgument req) override;
+
+private:
+ std::unique_ptr<HelpManager> m_helpManager;
};
QT_END_NAMESPACE
diff --git a/src/qmlls/qqmllintsuggestions.cpp b/src/qmlls/qqmllintsuggestions.cpp
index ab12195b4d..914437df3f 100644
--- a/src/qmlls/qqmllintsuggestions.cpp
+++ b/src/qmlls/qqmllintsuggestions.cpp
@@ -16,13 +16,14 @@
#include <QtCore/qxpfunctional.h>
#include <chrono>
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lintLog, "qt.languageserver.lint")
+
using namespace QLspSpecification;
using namespace QQmlJS::Dom;
using namespace Qt::StringLiterals;
-Q_LOGGING_CATEGORY(lintLog, "qt.languageserver.lint")
-
-QT_BEGIN_NAMESPACE
namespace QmlLsp {
static DiagnosticSeverity severityFromMsgType(QtMsgType t)
diff --git a/src/qmlls/qqmllscompletion.cpp b/src/qmlls/qqmllscompletion.cpp
index 8ecbcffc70..5f54597c78 100644
--- a/src/qmlls/qqmllscompletion.cpp
+++ b/src/qmlls/qqmllscompletion.cpp
@@ -3,14 +3,14 @@
#include "qqmllscompletion_p.h"
-using namespace QLspSpecification;
-using namespace QQmlJS::Dom;
-using namespace Qt::StringLiterals;
-
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(QQmlLSCompletionLog, "qt.languageserver.completions")
+using namespace QLspSpecification;
+using namespace QQmlJS::Dom;
+using namespace Qt::StringLiterals;
+
/*!
\class QQmlLSCompletion
\internal
@@ -149,7 +149,7 @@ QQmlLSCompletion::suggestBindingCompletion(const DomItem &itemAtPosition, BackIn
const DomItem owner = itemAtPosition.directParent().field(Fields::left);
auto expressionType = QQmlLSUtils::resolveExpressionType(
- owner, ResolveActualTypeForFieldMemberExpression);
+ owner, QQmlLSUtils::ResolveActualTypeForFieldMemberExpression);
return expressionType ? expressionType->semanticScope : QQmlJSScope::ConstPtr{};
}();
@@ -511,13 +511,13 @@ void QQmlLSCompletion::suggestJSExpressionCompletion(const DomItem &scriptIdenti
(askForCompletionOnDot ? scriptIdentifier : scriptIdentifier.directParent())
.field(Fields::left);
auto expressionType = QQmlLSUtils::resolveExpressionType(
- owner, ResolveActualTypeForFieldMemberExpression);
+ owner, QQmlLSUtils::ResolveActualTypeForFieldMemberExpression);
if (!expressionType || !expressionType->semanticScope)
return;
nearestScope = expressionType->semanticScope;
// Use root element scope to use find the enumerations
// This should be changed when we support usages in external files
- if (expressionType->type == QmlComponentIdentifier)
+ if (expressionType->type == QQmlLSUtils::QmlComponentIdentifier)
nearestScope = owner.rootQmlObject(GoTo::MostLikely).semanticScope();
if (expressionType->name) {
// note: you only get enumeration values in qualified expressions, never alone
@@ -529,7 +529,7 @@ void QQmlLSCompletion::suggestJSExpressionCompletion(const DomItem &scriptIdenti
enumerationCompletion(nearestScope, &usedNames, result);
}
- if (expressionType->type == EnumeratorIdentifier)
+ if (expressionType->type == QQmlLSUtils::EnumeratorIdentifier)
return;
}
}
@@ -823,7 +823,8 @@ void QQmlLSCompletion::insideBindingCompletion(const DomItem &currentItem,
if (cursorAfterColon(containingBinding, positionInfo)) {
suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
- if (auto type = QQmlLSUtils::resolveExpressionType(currentItem, ResolveOwnerType)) {
+ if (auto type = QQmlLSUtils::resolveExpressionType(currentItem,
+ QQmlLSUtils::ResolveOwnerType)) {
const QStringList names = currentItem.field(Fields::name).toString().split(u'.');
const QQmlJSScope *current = resolve(type->semanticScope.get(), names);
// add type names when binding to an object type or a property with var type
@@ -895,7 +896,7 @@ void QQmlLSCompletion::insideQmlFileCompletion(const DomItem &currentItem,
Generate the snippets for let, var and const variable declarations.
*/
void QQmlLSCompletion::suggestVariableDeclarationStatementCompletion(
- BackInsertIterator result, QQmlLSUtilsAppendOption option) const
+ BackInsertIterator result, AppendOption option) const
{
// let/var/const statement
for (auto view : std::array<QUtf8StringView, 3>{ "let", "var", "const" }) {
@@ -1104,7 +1105,7 @@ void QQmlLSCompletion::insideForStatementCompletion(const DomItem &parentForCont
if (betweenLocations(leftParenthesis, positionInfo, firstSemicolon)) {
suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
suggestVariableDeclarationStatementCompletion(result,
- QQmlLSUtilsAppendOption::AppendNothing);
+ AppendOption::AppendNothing);
return;
}
if (betweenLocations(firstSemicolon, positionInfo, secondSemicolon)
diff --git a/src/qmlls/qqmllscompletion_p.h b/src/qmlls/qqmllscompletion_p.h
index a31d3daebc..a371fd0315 100644
--- a/src/qmlls/qqmllscompletion_p.h
+++ b/src/qmlls/qqmllscompletion_p.h
@@ -31,12 +31,14 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QQmlLSCompletionLog)
-enum QQmlLSUtilsAppendOption { AppendSemicolon, AppendNothing };
class QQmlLSCompletion
{
using DomItem = QQmlJS::Dom::DomItem;
public:
+ enum class ImportCompletionType { None, Module, Version };
+ enum AppendOption { AppendSemicolon, AppendNothing };
+
QQmlLSCompletion(const QFactoryLoader &pluginLoader);
using CompletionItem = QLspSpecification::CompletionItem;
@@ -84,7 +86,7 @@ private:
void suggestJSStatementCompletion(const DomItem &currentItem, BackInsertIterator it) const;
void suggestCaseAndDefaultStatementCompletion(BackInsertIterator it) const;
void suggestVariableDeclarationStatementCompletion(
- BackInsertIterator it, QQmlLSUtilsAppendOption option = AppendSemicolon) const;
+ BackInsertIterator it, AppendOption option = AppendSemicolon) const;
void suggestJSExpressionCompletion(const DomItem &context, BackInsertIterator it) const;
diff --git a/src/qmlls/qqmllshelpplugininterface.cpp b/src/qmlls/qqmllshelpplugininterface.cpp
new file mode 100644
index 0000000000..62944d69e0
--- /dev/null
+++ b/src/qmlls/qqmllshelpplugininterface.cpp
@@ -0,0 +1,4 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmllshelpplugininterface_p.h"
diff --git a/src/qmlls/qqmllshelpplugininterface_p.h b/src/qmlls/qqmllshelpplugininterface_p.h
new file mode 100644
index 0000000000..280d7c3e5d
--- /dev/null
+++ b/src/qmlls/qqmllshelpplugininterface_p.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLLSHELPPLUGININTERFACE_H
+#define QQMLLSHELPPLUGININTERFACE_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 <QtCore/qstring.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qobject.h>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlLSHelpProviderBase
+{
+public:
+ struct DocumentLink
+ {
+ QUrl url;
+ QString title;
+ };
+
+public:
+ virtual ~QQmlLSHelpProviderBase() = default;
+ virtual bool registerDocumentation(const QString &documentationFileName) = 0;
+ [[nodiscard]] virtual QByteArray fileData(const QUrl &url) const = 0;
+ [[nodiscard]] virtual std::vector<DocumentLink> documentsForIdentifier(const QString &id) const = 0;
+ [[nodiscard]] virtual std::vector<DocumentLink>
+ documentsForIdentifier(const QString &id, const QString &filterName) const = 0;
+ [[nodiscard]] virtual std::vector<DocumentLink> documentsForKeyword(const QString &keyword) const = 0;
+ [[nodiscard]] virtual std::vector<DocumentLink>
+ documentsForKeyword(const QString &keyword, const QString &filterName) const = 0;
+ [[nodiscard]] virtual QStringList registeredNamespaces() const = 0;
+ [[nodiscard]] virtual QString error() const = 0;
+};
+
+class QQmlLSHelpPluginInterface
+{
+public:
+ QQmlLSHelpPluginInterface() = default;
+ virtual ~QQmlLSHelpPluginInterface() = default;
+ Q_DISABLE_COPY_MOVE(QQmlLSHelpPluginInterface)
+
+ virtual std::unique_ptr<QQmlLSHelpProviderBase> initialize(const QString &collectionFile,
+ QObject *parent) = 0;
+};
+
+#define QQmlLSHelpPluginInterface_iid "org.qt-project.Qt.QmlLS.HelpPlugin/1.0"
+Q_DECLARE_INTERFACE(QQmlLSHelpPluginInterface, QQmlLSHelpPluginInterface_iid)
+
+QT_END_NAMESPACE
+
+#endif // QQMLLSHELPPLUGININTERFACE_H
diff --git a/src/qmlls/qqmllshelputils.cpp b/src/qmlls/qqmllshelputils.cpp
new file mode 100644
index 0000000000..b74e8d0402
--- /dev/null
+++ b/src/qmlls/qqmllshelputils.cpp
@@ -0,0 +1,255 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qqmllshelputils_p.h"
+
+#include <QtQmlLS/private/qqmllsutils_p.h>
+#include <QtCore/private/qfactoryloader_p.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qdir.h>
+#include <QtQmlCompiler/private/qqmljstyperesolver_p.h>
+#include <optional>
+
+QT_BEGIN_NAMESPACE
+
+Q_STATIC_LOGGING_CATEGORY(QQmlLSHelpUtilsLog, "qt.languageserver.helpUtils")
+
+using namespace QQmlJS::Dom;
+
+static QStringList documentationFiles(const QString &qtInstallationPath)
+{
+ QStringList result;
+ QDirIterator dirIterator(qtInstallationPath, QStringList{ "*.qch"_L1 }, QDir::Files);
+ while (dirIterator.hasNext()) {
+ const auto fileInfo = dirIterator.nextFileInfo();
+ result << fileInfo.absoluteFilePath();
+ }
+ return result;
+}
+
+HelpManager::HelpManager()
+{
+ const QFactoryLoader pluginLoader(QQmlLSHelpPluginInterface_iid, u"/help"_s);
+ const auto keys = pluginLoader.metaDataKeys();
+ for (qsizetype i = 0; i < keys.size(); ++i) {
+ auto instance = qobject_cast<QQmlLSHelpPluginInterface *>(pluginLoader.instance(i));
+ if (instance) {
+ m_helpPlugin =
+ instance->initialize(QDir::tempPath() + "/collectionFile.qhc"_L1, nullptr);
+ break;
+ }
+ }
+}
+
+void HelpManager::setDocumentationRootPath(const QString &path)
+{
+ if (m_docRootPath == path)
+ return;
+ m_docRootPath = path;
+
+ const auto foundQchFiles = documentationFiles(path);
+ if (foundQchFiles.isEmpty()) {
+ qCWarning(QQmlLSHelpUtilsLog)
+ << "No documentation files found in the Qt doc installation path: " << path;
+ return;
+ }
+
+ return registerDocumentations(foundQchFiles);
+}
+
+QString HelpManager::documentationRootPath() const
+{
+ return m_docRootPath;
+}
+
+void HelpManager::registerDocumentations(const QStringList &docs) const
+{
+ if (!m_helpPlugin)
+ return;
+ std::for_each(docs.cbegin(), docs.cend(),
+ [this](const auto &file) { m_helpPlugin->registerDocumentation(file); });
+}
+
+std::optional<QByteArray> HelpManager::extractDocumentation(const DomItem &item) const
+{
+ if (item.internalKind() == DomType::ScriptIdentifierExpression) {
+ const auto resolvedType =
+ QQmlLSUtils::resolveExpressionType(item, QQmlLSUtils::ResolveOwnerType);
+ if (!resolvedType)
+ return std::nullopt;
+
+ return extractDocumentationForIdentifiers(item, resolvedType.value());
+ } else {
+ return extractDocumentationForDomElements(item);
+ }
+
+ Q_UNREACHABLE_RETURN(std::nullopt);
+}
+
+std::optional<QByteArray>
+HelpManager::extractDocumentationForIdentifiers(const DomItem &item,
+ QQmlLSUtils::ExpressionType expr) const
+{
+ const auto qmlFile = item.containingFile().as<QmlFile>();
+ if (!qmlFile)
+ return std::nullopt;
+ const auto links = collectDocumentationLinks(expr.semanticScope, qmlFile->typeResolver(),
+ expr.name.value());
+ switch (expr.type) {
+ case QQmlLSUtils::QmlObjectIdIdentifier:
+ case QQmlLSUtils::JavaScriptIdentifier:
+ case QQmlLSUtils::GroupedPropertyIdentifier:
+ case QQmlLSUtils::PropertyIdentifier: {
+ ExtractDocumentation extractor(DomType::PropertyDefinition);
+ return tryExtract(extractor, links, expr.name.value());
+ }
+ case QQmlLSUtils::PropertyChangedSignalIdentifier:
+ case QQmlLSUtils::PropertyChangedHandlerIdentifier:
+ case QQmlLSUtils::SignalIdentifier:
+ case QQmlLSUtils::SignalHandlerIdentifier:
+ case QQmlLSUtils::MethodIdentifier: {
+ ExtractDocumentation extractor(DomType::MethodInfo);
+ return tryExtract(extractor, links, expr.name.value());
+ }
+ case QQmlLSUtils::SingletonIdentifier:
+ case QQmlLSUtils::AttachedTypeIdentifier:
+ case QQmlLSUtils::QmlComponentIdentifier: {
+ ExtractDocumentation extractor(DomType::QmlObject);
+ return tryExtract(extractor, links, expr.name.value());
+ }
+
+ // Not implemented yet
+ case QQmlLSUtils::EnumeratorIdentifier:
+ case QQmlLSUtils::EnumeratorValueIdentifier:
+ default:
+ qCDebug(QQmlLSHelpUtilsLog)
+ << "Documentation extraction for" << expr.name.value() << "was not implemented";
+ return std::nullopt;
+ }
+ Q_UNREACHABLE_RETURN(std::nullopt);
+}
+
+std::optional<QByteArray> HelpManager::extractDocumentationForDomElements(const DomItem &item) const
+{
+ const auto qmlFile = item.containingFile().as<QmlFile>();
+ if (!qmlFile)
+ return std::nullopt;
+
+ const auto name = item.field(Fields::name).value().toString();
+ std::vector<QQmlLSHelpProviderBase::DocumentLink> links;
+ switch (item.internalKind()) {
+ case DomType::QmlObject: {
+ links = collectDocumentationLinks(item.nearestSemanticScope(), qmlFile->typeResolver(),
+ name);
+ break;
+ }
+ case DomType::PropertyDefinition: {
+ const auto scope =
+ QQmlLSUtils::findDefiningScopeForProperty(item.nearestSemanticScope(), name);
+ links = collectDocumentationLinks(scope, qmlFile->typeResolver(), name);
+ break;
+ }
+ case DomType::Binding: {
+ const auto scope =
+ QQmlLSUtils::findDefiningScopeForBinding(item.nearestSemanticScope(), name);
+ links = collectDocumentationLinks(scope, qmlFile->typeResolver(), name);
+ break;
+ }
+ case DomType::MethodInfo: {
+ const auto scope =
+ QQmlLSUtils::findDefiningScopeForMethod(item.nearestSemanticScope(), name);
+ links = collectDocumentationLinks(scope, qmlFile->typeResolver(), name);
+ break;
+ }
+ default:
+ qCDebug(QQmlLSHelpUtilsLog)
+ << item.internalKindStr() << "was not implemented for documentation extraction";
+ return std::nullopt;
+ }
+
+ ExtractDocumentation extractor(item.internalKind());
+ return tryExtract(extractor, links, name);
+}
+
+std::optional<QByteArray>
+HelpManager::tryExtract(ExtractDocumentation &extractor,
+ const std::vector<QQmlLSHelpProviderBase::DocumentLink> &links,
+ const QString &name) const
+{
+ if (!m_helpPlugin)
+ return std::nullopt;
+
+ for (auto &&link : links) {
+ const auto fileData = m_helpPlugin->fileData(link.url);
+ if (fileData.isEmpty()) {
+ qCDebug(QQmlLSHelpUtilsLog) << "No documentation found for" << link.url;
+ continue;
+ }
+ const auto &documentation = extractor.execute(QString::fromUtf8(fileData), name,
+ HtmlExtractor::ExtractionMode::Simplified);
+ if (documentation.isEmpty())
+ continue;
+ return documentation.toUtf8();
+ }
+
+ return std::nullopt;
+}
+
+std::optional<QByteArray>
+HelpManager::documentationForItem(const DomItem &file, QLspSpecification::Position position) const
+{
+ if (!m_helpPlugin)
+ return std::nullopt;
+
+ if (m_helpPlugin->registeredNamespaces().empty())
+ return std::nullopt;
+
+ std::optional<QByteArray> result;
+ const auto [line, character] = position;
+ const auto itemLocations = QQmlLSUtils::itemsFromTextLocation(file, line, character);
+
+ // Process found item's internalKind and fetch its documentation.
+ for (const auto &entry : itemLocations) {
+ result = extractDocumentation(entry.domItem);
+ if (result.has_value())
+ break;
+ }
+
+ return result;
+}
+
+/*
+ * Returns the list of potential documentation links for the given item.
+ * A keyword is not necessarily a unique name, so we need to find the scope where
+ * the keyword is defined. If the item is a property, method or binding, it will
+ * search for the defining scope and return the documentation links by looking at
+ * the imported names. If the item is a QmlObject, it will return the documentation
+ * links for qmlobject name.
+ */
+std::vector<QQmlLSHelpProviderBase::DocumentLink>
+HelpManager::collectDocumentationLinks(
+ const QQmlJSScope::ConstPtr &scope, const std::shared_ptr<QQmlJSTypeResolver> &typeResolver,
+ const QString &name) const
+{
+ if (!m_helpPlugin)
+ return {};
+ const auto potentialDocumentationLinks =
+ [this](const QQmlJSScope::ConstPtr &scope,
+ const std::shared_ptr<QQmlJSTypeResolver> &typeResolver)
+ -> std::vector<QQmlLSHelpProviderBase::DocumentLink> {
+ if (!scope || !typeResolver)
+ return {};
+
+ std::vector<QQmlLSHelpProviderBase::DocumentLink> links;
+ const auto docLinks = m_helpPlugin->documentsForKeyword(typeResolver->nameForType(scope));
+ std::copy(docLinks.cbegin(), docLinks.cend(), std::back_inserter(links));
+ return links;
+ };
+
+ // If the scope is not found for the defined scope, return all the links related to this name.
+ const auto result = potentialDocumentationLinks(scope, typeResolver);
+ return result.empty() ? m_helpPlugin->documentsForKeyword(name) : result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qmlls/qqmllshelputils_p.h b/src/qmlls/qqmllshelputils_p.h
new file mode 100644
index 0000000000..1f7e6f1f8b
--- /dev/null
+++ b/src/qmlls/qqmllshelputils_p.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLLSHELPUTILS_P_H
+#define QQMLLSHELPUTILS_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 <QtQmlLS/private/qqmllshelpplugininterface_p.h>
+#include <QtQmlLS/private/qqmllsutils_p.h>
+#include <QtQmlDom/private/qqmldomtop_p.h>
+#include <QtQmlLS/private/qdochtmlparser_p.h>
+#include <QtLanguageServer/private/qlanguageserverspectypes_p.h>
+
+#include <vector>
+#include <string>
+
+QT_BEGIN_NAMESPACE
+
+class HelpManager final
+{
+public:
+ HelpManager();
+ void setDocumentationRootPath(const QString &path);
+ [[nodiscard]] QString documentationRootPath() const;
+ [[nodiscard]] std::optional<QByteArray> documentationForItem(
+ const QQmlJS::Dom::DomItem &file, QLspSpecification::Position position) const;
+
+private:
+ [[nodiscard]] std::optional<QByteArray> extractDocumentationForIdentifiers(
+ const QQmlJS::Dom::DomItem &item, QQmlLSUtils::ExpressionType) const;
+ [[nodiscard]] std::optional<QByteArray> extractDocumentationForDomElements(
+ const QQmlJS::Dom::DomItem &item) const;
+ [[nodiscard]] std::optional<QByteArray> extractDocumentation(
+ const QQmlJS::Dom::DomItem &item) const;
+ [[nodiscard]] std::optional<QByteArray> tryExtract(ExtractDocumentation &extractor,
+ const std::vector<QQmlLSHelpProviderBase::DocumentLink> &links,
+ const QString &name) const;
+ [[nodiscard]] std::vector<QQmlLSHelpProviderBase::DocumentLink> collectDocumentationLinks(
+ const QQmlJSScope::ConstPtr &scope,
+ const std::shared_ptr<QQmlJSTypeResolver> &typeResolver,
+ const QString &name) const;
+ void registerDocumentations(const QStringList &docs) const;
+ std::unique_ptr<QQmlLSHelpProviderBase> m_helpPlugin;
+ QString m_docRootPath;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLLSHELPUTILS_P_H
diff --git a/src/qmlls/qqmllsutils.cpp b/src/qmlls/qqmllsutils.cpp
index bc9f21d7b9..9e535ed185 100644
--- a/src/qmlls/qqmllsutils.cpp
+++ b/src/qmlls/qqmllsutils.cpp
@@ -25,15 +25,15 @@
#include <utility>
#include <variant>
-using namespace QLspSpecification;
-using namespace QQmlJS::Dom;
-using namespace Qt::StringLiterals;
-
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(QQmlLSUtilsLog, "qt.languageserver.utils")
-QString QQmlLSUtils::qualifiersFrom(const DomItem &el)
+using namespace QQmlJS::Dom;
+using namespace Qt::StringLiterals;
+
+namespace QQmlLSUtils {
+QString qualifiersFrom(const DomItem &el)
{
const bool isAccess = QQmlLSUtils::isFieldMemberAccess(el);
if (!isAccess && !QQmlLSUtils::isFieldMemberExpression(el))
@@ -55,7 +55,7 @@ QString QQmlLSUtils::qualifiersFrom(const DomItem &el)
\internal
Helper to check if item is a Field Member Expression \c {<someExpression>.propertyName}.
*/
-bool QQmlLSUtils::isFieldMemberExpression(const DomItem &item)
+bool isFieldMemberExpression(const DomItem &item)
{
return item.internalKind() == DomType::ScriptBinaryExpression
&& item.field(Fields::operation).value().toInteger()
@@ -67,7 +67,7 @@ bool QQmlLSUtils::isFieldMemberExpression(const DomItem &item)
Helper to check if item is a Field Member Access \c memberAccess in
\c {<someExpression>.memberAccess}.
*/
-bool QQmlLSUtils::isFieldMemberAccess(const DomItem &item)
+bool isFieldMemberAccess(const DomItem &item)
{
auto parent = item.directParent();
if (!isFieldMemberExpression(parent))
@@ -86,7 +86,7 @@ bool QQmlLSUtils::isFieldMemberAccess(const DomItem &item)
FieldMemberExpression stopAtChild, or before processing a ScriptIdentifierExpression stopAtChild.
No early exits if stopAtChild is default constructed.
*/
-QStringList QQmlLSUtils::fieldMemberExpressionBits(const DomItem &item, const DomItem &stopAtChild)
+QStringList fieldMemberExpressionBits(const DomItem &item, const DomItem &stopAtChild)
{
const bool isAccess = isFieldMemberAccess(item);
const bool isExpression = isFieldMemberExpression(item);
@@ -127,12 +127,12 @@ QStringList QQmlLSUtils::fieldMemberExpressionBits(const DomItem &item, const Do
\sa QQmlLSUtils::qmlUriToLspUrl
*/
-QByteArray QQmlLSUtils::lspUriToQmlUrl(const QByteArray &uri)
+QByteArray lspUriToQmlUrl(const QByteArray &uri)
{
return uri;
}
-QByteArray QQmlLSUtils::qmlUrlToLspUri(const QByteArray &url)
+QByteArray qmlUrlToLspUri(const QByteArray &url)
{
return url;
}
@@ -146,10 +146,10 @@ QByteArray QQmlLSUtils::qmlUrlToLspUri(const QByteArray &url)
contains startLine, startColumn, endLine and endColumn, which must be computed from the actual
qml code.
*/
-QLspSpecification::Range QQmlLSUtils::qmlLocationToLspLocation(const QString &code,
- QQmlJS::SourceLocation qmlLocation)
+QLspSpecification::Range qmlLocationToLspLocation(const QString &code,
+ QQmlJS::SourceLocation qmlLocation)
{
- Range range;
+ QLspSpecification::Range range;
range.start.line = qmlLocation.startLine - 1;
range.start.character = qmlLocation.startColumn - 1;
@@ -169,7 +169,7 @@ QLspSpecification::Range QQmlLSUtils::qmlLocationToLspLocation(const QString &co
\sa QQmlLSUtils::textRowAndColumnFrom
*/
-qsizetype QQmlLSUtils::textOffsetFrom(const QString &text, int row, int column)
+qsizetype textOffsetFrom(const QString &text, int row, int column)
{
int targetLine = row;
qsizetype i = 0;
@@ -206,7 +206,7 @@ qsizetype QQmlLSUtils::textOffsetFrom(const QString &text, int row, int column)
\sa QQmlLSUtils::textOffsetFrom
*/
-QQmlLSUtilsTextPosition QQmlLSUtils::textRowAndColumnFrom(const QString &text, qsizetype offset)
+TextPosition textRowAndColumnFrom(const QString &text, qsizetype offset)
{
int row = 0;
int column = 0;
@@ -226,13 +226,11 @@ QQmlLSUtilsTextPosition QQmlLSUtils::textRowAndColumnFrom(const QString &text, q
return { row, column };
}
-static QList<QQmlLSUtilsItemLocation>::const_iterator
-handlePropertyDefinitionAndBindingOverlap(const QList<QQmlLSUtilsItemLocation> &items,
- qsizetype offsetInFile)
+static QList<ItemLocation>::const_iterator
+handlePropertyDefinitionAndBindingOverlap(const QList<ItemLocation> &items, qsizetype offsetInFile)
{
auto smallest = std::min_element(
- items.begin(), items.end(),
- [](const QQmlLSUtilsItemLocation &a, const QQmlLSUtilsItemLocation &b) {
+ items.begin(), items.end(), [](const ItemLocation &a, const ItemLocation &b) {
return a.fileLocation->info().fullRegion.length
< b.fileLocation->info().fullRegion.length;
});
@@ -250,8 +248,7 @@ handlePropertyDefinitionAndBindingOverlap(const QList<QQmlLSUtilsItemLocation> &
// get the smallest property definition to avoid getting the property definition that the
// current QmlObject is getting bound to!
auto smallestPropertyDefinition = std::min_element(
- items.begin(), items.end(),
- [](const QQmlLSUtilsItemLocation &a, const QQmlLSUtilsItemLocation &b) {
+ items.begin(), items.end(), [](const ItemLocation &a, const ItemLocation &b) {
// make property definition smaller to avoid getting smaller items that are not
// property definitions
const bool aIsPropertyDefinition =
@@ -279,8 +276,8 @@ handlePropertyDefinitionAndBindingOverlap(const QList<QQmlLSUtilsItemLocation> &
return smallest;
}
-static QList<QQmlLSUtilsItemLocation>
-filterItemsFromTextLocation(const QList<QQmlLSUtilsItemLocation> &items, qsizetype offsetInFile)
+static QList<ItemLocation> filterItemsFromTextLocation(const QList<ItemLocation> &items,
+ qsizetype offsetInFile)
{
if (items.size() < 2)
return items;
@@ -291,7 +288,7 @@ filterItemsFromTextLocation(const QList<QQmlLSUtilsItemLocation> &items, qsizety
// "contain" everything from their first-appearing to last-appearing property (e.g. also
// other stuff in between those two properties).
- QList<QQmlLSUtilsItemLocation> filteredItems;
+ QList<ItemLocation> filteredItems;
auto smallest = handlePropertyDefinitionAndBindingOverlap(items, offsetInFile);
@@ -323,17 +320,16 @@ filterItemsFromTextLocation(const QList<QQmlLSUtilsItemLocation> &items, qsizety
If line and character point between two objects, two objects might be returned.
If line and character point to whitespace, it might return an inner node of the QmlDom-Tree.
*/
-QList<QQmlLSUtilsItemLocation> QQmlLSUtils::itemsFromTextLocation(const DomItem &file, int line,
- int character)
+QList<ItemLocation> itemsFromTextLocation(const DomItem &file, int line, int character)
{
- QList<QQmlLSUtilsItemLocation> itemsFound;
+ QList<ItemLocation> itemsFound;
std::shared_ptr<QmlFile> filePtr = file.ownerAs<QmlFile>();
if (!filePtr)
return itemsFound;
FileLocations::Tree t = filePtr->fileLocationsTree();
Q_ASSERT(t);
QString code = filePtr->code(); // do something more advanced wrt to changes wrt to this->code?
- QList<QQmlLSUtilsItemLocation> toDo;
+ QList<ItemLocation> toDo;
qsizetype targetPos = textOffsetFrom(code, line, character);
Q_ASSERT(targetPos >= 0);
auto containsTarget = [targetPos](QQmlJS::SourceLocation l) {
@@ -344,13 +340,13 @@ QList<QQmlLSUtilsItemLocation> QQmlLSUtils::itemsFromTextLocation(const DomItem
}
};
if (containsTarget(t->info().fullRegion)) {
- QQmlLSUtilsItemLocation loc;
+ ItemLocation loc;
loc.domItem = file;
loc.fileLocation = t;
toDo.append(loc);
}
while (!toDo.isEmpty()) {
- QQmlLSUtilsItemLocation iLoc = toDo.last();
+ ItemLocation iLoc = toDo.last();
toDo.removeLast();
bool inParentButOutsideChildren = true;
@@ -361,7 +357,7 @@ QList<QQmlLSUtilsItemLocation> QQmlLSUtils::itemsFromTextLocation(const DomItem
Q_ASSERT(subLoc);
if (containsTarget(subLoc->info().fullRegion)) {
- QQmlLSUtilsItemLocation subItem;
+ ItemLocation subItem;
subItem.domItem = iLoc.domItem.path(it.key());
if (!subItem.domItem) {
qCDebug(QQmlLSUtilsLog)
@@ -390,7 +386,7 @@ QList<QQmlLSUtilsItemLocation> QQmlLSUtils::itemsFromTextLocation(const DomItem
return filtered;
}
-DomItem QQmlLSUtils::baseObject(const DomItem &object)
+DomItem baseObject(const DomItem &object)
{
DomItem prototypes;
DomItem qmlObject = object.qmlObject();
@@ -417,10 +413,9 @@ DomItem QQmlLSUtils::baseObject(const DomItem &object)
return base;
}
-static std::optional<QQmlLSUtilsLocation> locationFromDomItem(const DomItem &item,
- FileLocationRegion region)
+static std::optional<Location> locationFromDomItem(const DomItem &item, FileLocationRegion region)
{
- QQmlLSUtilsLocation location;
+ Location location;
location.filename = item.canonicalFilePath();
auto tree = FileLocations::treeOf(item);
@@ -446,7 +441,7 @@ static std::optional<QQmlLSUtilsLocation> locationFromDomItem(const DomItem &ite
For a \c Methodparameter, return the location of the type of the parameter.
Otherwise, return std::nullopt.
*/
-std::optional<QQmlLSUtilsLocation> QQmlLSUtils::findTypeDefinitionOf(const DomItem &object)
+std::optional<Location> findTypeDefinitionOf(const DomItem &object)
{
DomItem typeDefinition;
@@ -524,18 +519,18 @@ std::optional<QQmlLSUtilsLocation> QQmlLSUtils::findTypeDefinitionOf(const DomIt
break;
}
- auto scope = QQmlLSUtils::resolveExpressionType(
- object, QQmlLSUtilsResolveOptions::ResolveActualTypeForFieldMemberExpression);
+ auto scope = resolveExpressionType(
+ object, ResolveOptions::ResolveActualTypeForFieldMemberExpression);
if (!scope)
return {};
if (scope->type == QmlObjectIdIdentifier) {
- return QQmlLSUtilsLocation{ scope->semanticScope->filePath(),
- scope->semanticScope->sourceLocation() };
+ return Location{ scope->semanticScope->filePath(),
+ scope->semanticScope->sourceLocation() };
}
- typeDefinition = QQmlLSUtils::sourceLocationToDomItem(
- object.containingFile(), scope->semanticScope->sourceLocation());
+ typeDefinition = sourceLocationToDomItem(object.containingFile(),
+ scope->semanticScope->sourceLocation());
return locationFromDomItem(typeDefinition.component(),
FileLocationRegion::IdentifierRegion);
}
@@ -602,7 +597,7 @@ struct SignalOrProperty
or handler.
*/
QString name;
- QQmlLSUtilsIdentifierType type;
+ IdentifierType type;
};
/*!
@@ -716,10 +711,12 @@ static QStringList namesOfPossibleUsages(const QString &name,
}
template<typename Predicate>
-QQmlJSScope::ConstPtr findDefiningScopeIf(QQmlJSScope::ConstPtr referrerScope, Predicate &&check)
+QQmlJSScope::ConstPtr findDefiningScopeIf(
+ const QQmlJSScope::ConstPtr &referrerScope, Predicate &&check)
{
QQmlJSScope::ConstPtr result;
- QQmlJSUtils::searchBaseAndExtensionTypes(referrerScope, [&](QQmlJSScope::ConstPtr scope) {
+ QQmlJSUtils::searchBaseAndExtensionTypes(
+ referrerScope, [&](const QQmlJSScope::ConstPtr &scope) {
if (check(scope)) {
result = scope;
return true;
@@ -737,8 +734,8 @@ QQmlJSScope::ConstPtr findDefiningScopeIf(QQmlJSScope::ConstPtr referrerScope, P
Starts looking for the name starting from the given scope and traverse through base and
extension types.
*/
-static QQmlJSScope::ConstPtr findDefiningScopeForProperty(QQmlJSScope::ConstPtr referrerScope,
- const QString &nameToCheck)
+QQmlJSScope::ConstPtr findDefiningScopeForProperty(const QQmlJSScope::ConstPtr &referrerScope,
+ const QString &nameToCheck)
{
return findDefiningScopeIf(referrerScope, [&nameToCheck](const QQmlJSScope::ConstPtr &scope) {
return scope->hasOwnProperty(nameToCheck);
@@ -751,8 +748,8 @@ See also findDefiningScopeForProperty().
Special case: you can also bind to a signal handler.
*/
-static QQmlJSScope::ConstPtr findDefiningScopeForBinding(QQmlJSScope::ConstPtr referrerScope,
- const QString &nameToCheck)
+QQmlJSScope::ConstPtr findDefiningScopeForBinding(const QQmlJSScope::ConstPtr &referrerScope,
+ const QString &nameToCheck)
{
return findDefiningScopeIf(referrerScope, [&nameToCheck](const QQmlJSScope::ConstPtr &scope) {
return scope->hasOwnProperty(nameToCheck) || scope->hasOwnMethod(nameToCheck);
@@ -763,8 +760,8 @@ static QQmlJSScope::ConstPtr findDefiningScopeForBinding(QQmlJSScope::ConstPtr r
\internal
See also findDefiningScopeForProperty().
*/
-static QQmlJSScope::ConstPtr findDefiningScopeForMethod(QQmlJSScope::ConstPtr referrerScope,
- const QString &nameToCheck)
+QQmlJSScope::ConstPtr findDefiningScopeForMethod(const QQmlJSScope::ConstPtr &referrerScope,
+ const QString &nameToCheck)
{
return findDefiningScopeIf(referrerScope, [&nameToCheck](const QQmlJSScope::ConstPtr &scope) {
return scope->hasOwnMethod(nameToCheck);
@@ -775,8 +772,8 @@ static QQmlJSScope::ConstPtr findDefiningScopeForMethod(QQmlJSScope::ConstPtr re
\internal
See also findDefiningScopeForProperty().
*/
-static QQmlJSScope::ConstPtr findDefiningScopeForEnumeration(QQmlJSScope::ConstPtr referrerScope,
- const QString &nameToCheck)
+QQmlJSScope::ConstPtr findDefiningScopeForEnumeration(const QQmlJSScope::ConstPtr &referrerScope,
+ const QString &nameToCheck)
{
return findDefiningScopeIf(referrerScope, [&nameToCheck](const QQmlJSScope::ConstPtr &scope) {
return scope->hasOwnEnumeration(nameToCheck);
@@ -787,8 +784,8 @@ static QQmlJSScope::ConstPtr findDefiningScopeForEnumeration(QQmlJSScope::ConstP
\internal
See also findDefiningScopeForProperty().
*/
-static QQmlJSScope::ConstPtr findDefiningScopeForEnumerationKey(QQmlJSScope::ConstPtr referrerScope,
- const QString &nameToCheck)
+QQmlJSScope::ConstPtr findDefiningScopeForEnumerationKey(const QQmlJSScope::ConstPtr &referrerScope,
+ const QString &nameToCheck)
{
return findDefiningScopeIf(referrerScope, [&nameToCheck](const QQmlJSScope::ConstPtr &scope) {
return scope->hasOwnEnumerationKey(nameToCheck);
@@ -817,38 +814,41 @@ static FieldFilter filterForFindUsages()
return filter;
};
-static void findUsagesOfNonJSIdentifiers(const DomItem &item, const QString &name,
- QList<QQmlLSUtilsLocation> &result)
+static void findUsagesOfNonJSIdentifiers(const DomItem &item, const QString &name, Usages &result)
{
- const auto expressionType = QQmlLSUtils::resolveExpressionType(item, ResolveOwnerType);
+ const auto expressionType = resolveExpressionType(item, ResolveOwnerType);
if (!expressionType)
return;
+ // for Qml file components: add their filename as an usage for the renaming operation
+ if (expressionType->type == QmlComponentIdentifier
+ && !expressionType->semanticScope->isInlineComponent()) {
+ result.appendFilenameUsage(expressionType->semanticScope->filePath());
+ }
+
const QStringList namesToCheck = namesOfPossibleUsages(name, item, expressionType->semanticScope);
- const auto addLocationIfTypeMatchesTarget = [&result,
- &expressionType](const DomItem &toBeResolved,
- FileLocationRegion subRegion) {
- const auto currentType = QQmlLSUtils::resolveExpressionType(
- toBeResolved, QQmlLSUtilsResolveOptions::ResolveOwnerType);
- if (!currentType)
- return;
-
- const QQmlJSScope::ConstPtr target = expressionType->semanticScope;
- const QQmlJSScope::ConstPtr current = currentType->semanticScope;
- if (target == current) {
- auto tree = FileLocations::treeOf(toBeResolved);
- QQmlJS::SourceLocation sourceLocation;
-
- sourceLocation = FileLocations::region(tree, subRegion);
- if (!sourceLocation.isValid())
- return;
-
- QQmlLSUtilsLocation location{ toBeResolved.canonicalFilePath(), sourceLocation };
- if (!result.contains(location))
- result.append(location);
- }
- };
+ const auto addLocationIfTypeMatchesTarget =
+ [&result, &expressionType](const DomItem &toBeResolved, FileLocationRegion subRegion) {
+ const auto currentType =
+ resolveExpressionType(toBeResolved, ResolveOptions::ResolveOwnerType);
+ if (!currentType)
+ return;
+
+ const QQmlJSScope::ConstPtr target = expressionType->semanticScope;
+ const QQmlJSScope::ConstPtr current = currentType->semanticScope;
+ if (target == current) {
+ auto tree = FileLocations::treeOf(toBeResolved);
+ QQmlJS::SourceLocation sourceLocation;
+
+ sourceLocation = FileLocations::region(tree, subRegion);
+ if (!sourceLocation.isValid())
+ return;
+
+ Location location{ toBeResolved.canonicalFilePath(), sourceLocation };
+ result.appendUsage(location);
+ }
+ };
auto findUsages = [&addLocationIfTypeMatchesTarget, &name,
&namesToCheck](Path, const DomItem &current, bool) -> bool {
@@ -923,8 +923,8 @@ static void findUsagesOfNonJSIdentifiers(const DomItem &item, const QString &nam
}
}
-static QQmlLSUtilsLocation locationFromJSIdentifierDefinition(const DomItem &definitionOfItem,
- const QString &name)
+static Location locationFromJSIdentifierDefinition(const DomItem &definitionOfItem,
+ const QString &name)
{
Q_ASSERT_X(!definitionOfItem.semanticScope().isNull()
&& definitionOfItem.semanticScope()->ownJSIdentifier(name).has_value(),
@@ -934,12 +934,11 @@ static QQmlLSUtilsLocation locationFromJSIdentifierDefinition(const DomItem &def
QQmlJS::SourceLocation location =
definitionOfItem.semanticScope()->ownJSIdentifier(name).value().location;
- QQmlLSUtilsLocation result = { definitionOfItem.canonicalFilePath(), location };
+ Location result = { definitionOfItem.canonicalFilePath(), location };
return result;
}
-static void findUsagesHelper(
- const DomItem &item, const QString &name, QList<QQmlLSUtilsLocation> &result)
+static void findUsagesHelper(const DomItem &item, const QString &name, Usages &result)
{
qCDebug(QQmlLSUtilsLog) << "Looking for JS identifier with name" << name;
DomItem definitionOfItem = findJSIdentifierDefinition(item, name);
@@ -965,9 +964,9 @@ static void findUsagesHelper(
}
const QQmlJS::SourceLocation location = fileLocation->info().fullRegion;
const QString fileName = item.canonicalFilePath();
- result.append({ fileName, location });
+ result.appendUsage({ fileName, location });
return true;
- } else if (QQmlJSScope::ConstPtr scope = item.semanticScope();
+ } else if (const QQmlJSScope::ConstPtr scope = item.semanticScope();
scope && scope->ownJSIdentifier(name)) {
// current JS identifier has been redefined, do not visit children
return false;
@@ -976,15 +975,13 @@ static void findUsagesHelper(
},
emptyChildrenVisitor, filterForFindUsages());
- const QQmlLSUtilsLocation definition =
- locationFromJSIdentifierDefinition(definitionOfItem, name);
- if (!result.contains(definition))
- result.append(definition);
+ const Location definition = locationFromJSIdentifierDefinition(definitionOfItem, name);
+ result.appendUsage(definition);
}
-QList<QQmlLSUtilsLocation> QQmlLSUtils::findUsagesOf(const DomItem &item)
+Usages findUsagesOf(const DomItem &item)
{
- QList<QQmlLSUtilsLocation> result;
+ Usages result;
switch (item.internalKind()) {
case DomType::ScriptIdentifierExpression: {
@@ -1022,30 +1019,32 @@ QList<QQmlLSUtilsLocation> QQmlLSUtils::findUsagesOf(const DomItem &item)
return result;
}
- std::sort(result.begin(), result.end());
+ result.sort();
if (QQmlLSUtilsLog().isDebugEnabled()) {
- qCDebug(QQmlLSUtilsLog) << "Found following usages:";
- for (auto r : result) {
+ qCDebug(QQmlLSUtilsLog) << "Found following usages in files:";
+ for (auto r : result.usagesInFile()) {
qCDebug(QQmlLSUtilsLog)
<< r.filename << " @ " << r.sourceLocation.startLine << ":"
<< r.sourceLocation.startColumn << " with length " << r.sourceLocation.length;
}
+ qCDebug(QQmlLSUtilsLog) << "And following usages in file names:"
+ << result.usagesInFilename();
}
return result;
}
-static std::optional<QQmlLSUtilsIdentifierType>
-hasMethodOrSignal(const QQmlJSScope::ConstPtr &scope, const QString &name)
+static std::optional<IdentifierType> hasMethodOrSignal(const QQmlJSScope::ConstPtr &scope,
+ const QString &name)
{
auto methods = scope->methods(name);
if (methods.isEmpty())
return {};
const bool isSignal = methods.front().methodType() == QQmlJSMetaMethodType::Signal;
- QQmlLSUtilsIdentifierType type = isSignal ? QQmlLSUtilsIdentifierType::SignalIdentifier
- : QQmlLSUtilsIdentifierType::MethodIdentifier;
+ IdentifierType type =
+ isSignal ? IdentifierType::SignalIdentifier : IdentifierType::MethodIdentifier;
return type;
}
@@ -1059,24 +1058,22 @@ linting module already warns about calling methods from parent scopes.
Note: in QML, one can only call methods from the current scope, and from the QML file root scope.
Everything else needs a qualifier.
*/
-static std::optional<QQmlLSUtilsExpressionType>
+static std::optional<ExpressionType>
methodFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QString &name,
- QQmlLSUtilsResolveOptions options)
+ ResolveOptions options)
{
for (QQmlJSScope::ConstPtr current = referrerScope; current; current = current->parentScope()) {
if (auto type = hasMethodOrSignal(current, name)) {
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{ name,
- findDefiningScopeForMethod(current, name),
- *type };
+ return ExpressionType{ name, findDefiningScopeForMethod(current, name), *type };
case ResolveActualTypeForFieldMemberExpression:
// QQmlJSScopes were not implemented for methods yet, but JS functions have methods
// and properties see
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
// for the list of properties/methods of functions. Therefore return a null scope.
// see also code below for non-qualified method access
- return QQmlLSUtilsExpressionType{ name, {}, *type };
+ return ExpressionType{ name, {}, *type };
}
}
@@ -1084,13 +1081,11 @@ methodFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QStrin
if (auto type = hasMethodOrSignal(current, *signalName)) {
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
- name, findDefiningScopeForMethod(current, *signalName),
- SignalHandlerIdentifier
- };
+ return ExpressionType{ name, findDefiningScopeForMethod(current, *signalName),
+ SignalHandlerIdentifier };
case ResolveActualTypeForFieldMemberExpression:
// Properties and methods of JS methods are not supported yet
- return QQmlLSUtilsExpressionType{ name, {}, SignalHandlerIdentifier };
+ return ExpressionType{ name, {}, SignalHandlerIdentifier };
}
}
}
@@ -1103,9 +1098,9 @@ methodFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QStrin
\internal
See comment on methodFromReferrerScope: the same applies to properties.
*/
-static std::optional<QQmlLSUtilsExpressionType>
+static std::optional<ExpressionType>
propertyFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QString &propertyName,
- QQmlLSUtilsResolveOptions options)
+ ResolveOptions options)
{
for (QQmlJSScope::ConstPtr current = referrerScope; current; current = current->parentScope()) {
const auto resolved = resolveNameInQmlScope(propertyName, current);
@@ -1115,13 +1110,11 @@ propertyFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QStr
if (auto property = current->property(resolved->name); property.isValid()) {
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
- propertyName, findDefiningScopeForProperty(current, propertyName),
- resolved->type
- };
+ return ExpressionType{ propertyName,
+ findDefiningScopeForProperty(current, propertyName),
+ resolved->type };
case ResolveActualTypeForFieldMemberExpression:
- return QQmlLSUtilsExpressionType{ propertyName, property.type(),
- resolved->type };
+ return ExpressionType{ propertyName, property.type(), resolved->type };
}
}
}
@@ -1135,23 +1128,20 @@ See comment on methodFromReferrerScope: the same applies to property bindings.
If resolver is not null then it is used to resolve the id with which a generalized grouped
properties starts.
*/
-static std::optional<QQmlLSUtilsExpressionType>
+static std::optional<ExpressionType>
propertyBindingFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, const QString &name,
- QQmlLSUtilsResolveOptions options,
- QQmlJSTypeResolver *resolverForIds)
+ ResolveOptions options, QQmlJSTypeResolver *resolverForIds)
{
- auto bindings = referrerScope->propertyBindings(name);
+ const auto bindings = referrerScope->propertyBindings(name);
if (bindings.isEmpty())
return {};
- const auto binding = bindings.front();
-
- if ((binding.bindingType() != QQmlSA::BindingType::AttachedProperty)
- && (binding.bindingType() != QQmlSA::BindingType::GroupProperty))
+ const auto binding = bindings.begin();
+ const auto bindingType = binding->bindingType();
+ const bool bindingIsAttached = bindingType == QQmlSA::BindingType::AttachedProperty;
+ if (!bindingIsAttached && bindingType != QQmlSA::BindingType::GroupProperty)
return {};
- const bool bindingIsAttached = binding.bindingType() == QQmlSA::BindingType::AttachedProperty;
-
// Generalized grouped properties, like Bindings or PropertyChanges, for example, have bindings
// starting in an id (like `someId.someProperty: ...`).
// If `someid` is not a property and is a deferred name, then it should be an id.
@@ -1160,38 +1150,36 @@ propertyBindingFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, con
if (!resolverForIds)
return {};
- QQmlJSRegisterContent fromId = resolverForIds->scopedType(
- referrerScope, name, QQmlJSRegisterContent::InvalidLookupIndex,
- AssumeComponentsAreBound);
- if (fromId.variant() == QQmlJSRegisterContent::ObjectById)
- return QQmlLSUtilsExpressionType{ name, fromId.type(), QmlObjectIdIdentifier };
-
- return QQmlLSUtilsExpressionType{ name, {}, QmlObjectIdIdentifier };
+ return ExpressionType {
+ name,
+ resolverForIds->typeForId(referrerScope, name, AssumeComponentsAreBound),
+ QmlObjectIdIdentifier
+ };
}
const auto typeIdentifier =
bindingIsAttached ? AttachedTypeIdentifier : GroupedPropertyIdentifier;
- const auto getScope = [&bindingIsAttached, &binding]() -> QQmlJSScope::ConstPtr {
+ const auto getScope = [bindingIsAttached, binding]() -> QQmlJSScope::ConstPtr {
if (bindingIsAttached)
- return binding.attachingType();
+ return binding->attachingType();
- return binding.groupType();
+ return binding->groupType();
};
switch (options) {
case ResolveOwnerType: {
- return QQmlLSUtilsExpressionType{
- name,
- // note: always return the type of the attached type as the owner.
- // Find usages on "Keys.", for example, should yield all usages of the "Keys"
- // attached property.
- bindingIsAttached ? getScope() : findDefiningScopeForProperty(referrerScope, name),
- typeIdentifier
- };
+ return ExpressionType{ name,
+ // note: always return the type of the attached type as the owner.
+ // Find usages on "Keys.", for example, should yield all usages of
+ // the "Keys" attached property.
+ bindingIsAttached
+ ? getScope()
+ : findDefiningScopeForProperty(referrerScope, name),
+ typeIdentifier };
}
case ResolveActualTypeForFieldMemberExpression:
- return QQmlLSUtilsExpressionType{ name, getScope(), typeIdentifier };
+ return ExpressionType{ name, getScope(), typeIdentifier };
}
Q_UNREACHABLE_RETURN({});
}
@@ -1200,7 +1188,8 @@ propertyBindingFromReferrerScope(const QQmlJSScope::ConstPtr &referrerScope, con
Finds the scope within the special elements like Connections,
PropertyChanges, Bindings or AnchorChanges.
*/
-static QQmlJSScope::ConstPtr findScopeOfSpecialItems(QQmlJSScope::ConstPtr scope, const DomItem &item)
+static QQmlJSScope::ConstPtr findScopeOfSpecialItems(
+ const QQmlJSScope::ConstPtr &scope, const DomItem &item)
{
if (!scope)
return {};
@@ -1211,7 +1200,7 @@ static QQmlJSScope::ConstPtr findScopeOfSpecialItems(QQmlJSScope::ConstPtr scope
u"QQuickAnchorChanges"_s};
const auto special = QQmlJSUtils::searchBaseAndExtensionTypes(
- scope, [&specialItems](QQmlJSScope::ConstPtr visitedScope) {
+ scope, [&specialItems](const QQmlJSScope::ConstPtr &visitedScope) {
const auto typeName = visitedScope->internalName();
if (specialItems.contains(typeName))
return true;
@@ -1245,28 +1234,25 @@ static QQmlJSScope::ConstPtr findScopeOfSpecialItems(QQmlJSScope::ConstPtr scope
return {};
// Note: It does not have to be an ID. It can be a property.
- return resolver->containedType(resolver->scopedType(scope, targetName));
- } else {
- if (item.internalKind() == DomType::Binding &&
- item.field(Fields::bindingType).value().toInteger() == int(BindingType::OnBinding)) {
- // Binding on sth : {} syntax
- // Target scope is the current scope
- return scope;
- }
- return scope->parentScope();
+ return resolver->scopedType(scope, targetName);
}
- return {};
+ if (item.internalKind() == DomType::Binding &&
+ item.field(Fields::bindingType).value().toInteger() == int(BindingType::OnBinding)) {
+ // Binding on sth : {} syntax
+ // Target scope is the current scope
+ return scope;
+ }
+ return scope->parentScope();
}
-static std::optional<QQmlLSUtilsExpressionType>
-resolveFieldMemberExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions options)
+static std::optional<ExpressionType> resolveFieldMemberExpressionType(const DomItem &item,
+ ResolveOptions options)
{
const QString name = item.field(Fields::identifier).value().toString();
DomItem parent = item.directParent();
- auto owner = QQmlLSUtils::resolveExpressionType(
- parent.field(Fields::left),
- QQmlLSUtilsResolveOptions::ResolveActualTypeForFieldMemberExpression);
+ auto owner = resolveExpressionType(parent.field(Fields::left),
+ ResolveOptions::ResolveActualTypeForFieldMemberExpression);
if (!owner)
return {};
@@ -1289,11 +1275,11 @@ resolveFieldMemberExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions
.rootQmlObject(GoTo::MostLikely)
.semanticScope();
if (scope->hasEnumerationKey(name)) {
- return QQmlLSUtilsExpressionType{name, scope, EnumeratorValueIdentifier};
+ return ExpressionType{ name, scope, EnumeratorValueIdentifier };
}
// Or it is a enum name <TypeName>.<EnumName>.<EnumValue>
else if (scope->hasEnumeration(name)) {
- return QQmlLSUtilsExpressionType{name, scope, EnumeratorIdentifier};
+ return ExpressionType{ name, scope, EnumeratorIdentifier };
}
// check inline components <TypeName>.<InlineComponentName>
@@ -1301,7 +1287,7 @@ resolveFieldMemberExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions
end = owner->semanticScope->childScopesEnd();
it != end; ++it) {
if ((*it)->inlineComponentName() == name) {
- return QQmlLSUtilsExpressionType{ name, *it, QmlComponentIdentifier };
+ return ExpressionType{ name, *it, QmlComponentIdentifier };
}
}
return {};
@@ -1311,30 +1297,28 @@ resolveFieldMemberExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions
return owner;
}
-static std::optional<QQmlLSUtilsExpressionType>
-resolveIdentifierExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions options)
+static std::optional<ExpressionType> resolveIdentifierExpressionType(const DomItem &item,
+ ResolveOptions options)
{
- if (QQmlLSUtils::isFieldMemberAccess(item)) {
+ if (isFieldMemberAccess(item)) {
return resolveFieldMemberExpressionType(item, options);
}
const QString name = item.field(Fields::identifier).value().toString();
- if (DomItem definitionOfItem = findJSIdentifierDefinition(item, name)) {
+ if (const DomItem definitionOfItem = findJSIdentifierDefinition(item, name)) {
Q_ASSERT_X(!definitionOfItem.semanticScope().isNull()
&& definitionOfItem.semanticScope()->ownJSIdentifier(name),
"QQmlLSUtils::findDefinitionOf",
"JS definition does not actually define the JS identifer. "
"It should be empty.");
- auto scope = definitionOfItem.semanticScope();
- auto jsIdentifier = scope->ownJSIdentifier(name);
- if (jsIdentifier->scope) {
- return QQmlLSUtilsExpressionType{ name, jsIdentifier->scope.toStrongRef(),
- QQmlLSUtilsIdentifierType::JavaScriptIdentifier };
- } else {
- return QQmlLSUtilsExpressionType{ name, scope,
- QQmlLSUtilsIdentifierType::JavaScriptIdentifier };
- }
+ const auto scope = definitionOfItem.semanticScope();
+ const auto jsIdentifier = scope->ownJSIdentifier(name);
+ return ExpressionType {
+ name,
+ jsIdentifier->scope ? QQmlJSScope::ConstPtr(jsIdentifier->scope.toStrongRef()) : scope,
+ IdentifierType::JavaScriptIdentifier
+ };
}
const auto referrerScope = item.nearestSemanticScope();
@@ -1350,53 +1334,50 @@ resolveIdentifierExpressionType(const DomItem &item, QQmlLSUtilsResolveOptions o
return {};
// check if its found as a property binding
- if (auto scope = propertyBindingFromReferrerScope(referrerScope, name, options, resolver.get()))
+ if (const auto scope = propertyBindingFromReferrerScope(
+ referrerScope, name, options, resolver.get())) {
return *scope;
+ }
// check if its an (unqualified) property
- if (auto scope = propertyFromReferrerScope(referrerScope, name, options))
+ if (const auto scope = propertyFromReferrerScope(referrerScope, name, options))
return *scope;
// Returns the baseType, can't use it with options.
- if (auto scope = resolver->typeForName(name)) {
+ if (const auto scope = resolver->typeForName(name)) {
if (scope->isSingleton())
- return QQmlLSUtilsExpressionType{ name, scope,
- QQmlLSUtilsIdentifierType::SingletonIdentifier };
+ return ExpressionType{ name, scope, IdentifierType::SingletonIdentifier };
- if (auto attachedScope = scope->attachedType()) {
- return QQmlLSUtilsExpressionType{
- name, attachedScope, QQmlLSUtilsIdentifierType::AttachedTypeIdentifier
- };
- }
+ if (const auto attachedScope = scope->attachedType())
+ return ExpressionType{ name, attachedScope, IdentifierType::AttachedTypeIdentifier };
// its a (inline) component!
- return QQmlLSUtilsExpressionType{ name, scope, QmlComponentIdentifier };
+ return ExpressionType{ name, scope, QmlComponentIdentifier };
}
// check if its an id
- QQmlJSRegisterContent fromId =
- resolver->scopedType(referrerScope, name, QQmlJSRegisterContent::InvalidLookupIndex,
- AssumeComponentsAreBound);
- if (fromId.variant() == QQmlJSRegisterContent::ObjectById)
- return QQmlLSUtilsExpressionType{ name, fromId.type(), QmlObjectIdIdentifier };
+ if (const QQmlJSScope::ConstPtr fromId
+ = resolver->typeForId(referrerScope, name, AssumeComponentsAreBound)) {
+ return ExpressionType{ name, fromId, QmlObjectIdIdentifier };
+ }
const QQmlJSScope::ConstPtr jsGlobal = resolver->jsGlobalObject();
// check if its a JS global method
- if (auto scope = methodFromReferrerScope(jsGlobal, name, options))
+ if (const auto scope = methodFromReferrerScope(jsGlobal, name, options))
return scope;
// check if its an JS global property
- if (auto scope = propertyFromReferrerScope(jsGlobal, name, options))
+ if (const auto scope = propertyFromReferrerScope(jsGlobal, name, options))
return *scope;
return {};
}
-static std::optional<QQmlLSUtilsExpressionType>
+static std::optional<ExpressionType>
resolveSignalOrPropertyExpressionType(const QString &name, const QQmlJSScope::ConstPtr &scope,
- QQmlLSUtilsResolveOptions options)
+ ResolveOptions options)
{
- auto signalOrProperty = resolveNameInQmlScope(name, scope);
+ const auto signalOrProperty = resolveNameInQmlScope(name, scope);
if (!signalOrProperty)
return {};
@@ -1404,20 +1385,18 @@ resolveSignalOrPropertyExpressionType(const QString &name, const QQmlJSScope::Co
case PropertyIdentifier:
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{ name, findDefiningScopeForProperty(scope, name),
- signalOrProperty->type };
+ return ExpressionType{ name, findDefiningScopeForProperty(scope, name),
+ signalOrProperty->type };
case ResolveActualTypeForFieldMemberExpression:
- return QQmlLSUtilsExpressionType{ name, scope->property(name).type(),
- signalOrProperty->type };
+ return ExpressionType{ name, scope->property(name).type(), signalOrProperty->type };
}
Q_UNREACHABLE_RETURN({});
case PropertyChangedHandlerIdentifier:
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
- name, findDefiningScopeForProperty(scope, signalOrProperty->name),
- signalOrProperty->type
- };
+ return ExpressionType{ name,
+ findDefiningScopeForProperty(scope, signalOrProperty->name),
+ signalOrProperty->type };
case ResolveActualTypeForFieldMemberExpression:
// Properties and methods are not implemented on methods.
Q_UNREACHABLE_RETURN({});
@@ -1429,8 +1408,8 @@ resolveSignalOrPropertyExpressionType(const QString &name, const QQmlJSScope::Co
case MethodIdentifier:
switch (options) {
case ResolveOwnerType: {
- return QQmlLSUtilsExpressionType{ name, findDefiningScopeForMethod(scope, name),
- signalOrProperty->type };
+ return ExpressionType{ name, findDefiningScopeForMethod(scope, name),
+ signalOrProperty->type };
}
case ResolveActualTypeForFieldMemberExpression:
// Properties and methods are not implemented on methods.
@@ -1447,9 +1426,8 @@ resolveSignalOrPropertyExpressionType(const QString &name, const QQmlJSScope::Co
Resolves the type of the given DomItem, when possible (e.g., when there are enough type
annotations).
*/
-std::optional<QQmlLSUtilsExpressionType>
-QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
- QQmlLSUtilsResolveOptions options)
+std::optional<ExpressionType> resolveExpressionType(const QQmlJS::Dom::DomItem &item,
+ ResolveOptions options)
{
switch (item.internalKind()) {
case DomType::ScriptIdentifierExpression: {
@@ -1461,8 +1439,7 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
const auto &scope = propertyDefinition->semanticScope();
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{ propertyDefinition->name, scope,
- PropertyIdentifier };
+ return ExpressionType{ propertyDefinition->name, scope, PropertyIdentifier };
case ResolveActualTypeForFieldMemberExpression:
// There should not be any PropertyDefinition inside a FieldMemberExpression.
Q_UNREACHABLE_RETURN({});
@@ -1480,15 +1457,16 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
const QString name = binding->name();
if (name == u"id")
- return QQmlLSUtilsExpressionType{ name, owner.value(), QmlObjectIdIdentifier };
+ return ExpressionType{ name, owner.value(), QmlObjectIdIdentifier };
- if (QQmlJSScope::ConstPtr targetScope = findScopeOfSpecialItems(owner.value(), item)) {
+ if (const QQmlJSScope::ConstPtr targetScope
+ = findScopeOfSpecialItems(owner.value(), item)) {
const auto signalOrProperty = resolveNameInQmlScope(name, targetScope);
if (!signalOrProperty)
return {};
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
+ return ExpressionType{
name, findDefiningScopeForBinding(targetScope, signalOrProperty->name),
signalOrProperty->type
};
@@ -1515,13 +1493,13 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
const bool isComponent = name.front().isUpper();
if (isComponent)
scope = scope->baseType();
- const QQmlLSUtilsIdentifierType type =
+ const IdentifierType type =
isComponent ? QmlComponentIdentifier : GroupedPropertyIdentifier;
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{ name, scope, type };
+ return ExpressionType{ name, scope, type };
case ResolveActualTypeForFieldMemberExpression:
- return QQmlLSUtilsExpressionType{ name, scope, type};
+ return ExpressionType{ name, scope, type };
}
}
return {};
@@ -1539,20 +1517,20 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
name = name.sliced(dotIndex + 1);
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{ name, scope, QmlComponentIdentifier };
+ return ExpressionType{ name, scope, QmlComponentIdentifier };
case ResolveActualTypeForFieldMemberExpression:
- return QQmlLSUtilsExpressionType{ name, scope, QmlComponentIdentifier };
+ return ExpressionType{ name, scope, QmlComponentIdentifier };
}
Q_UNREACHABLE_RETURN({});
}
case DomType::MethodInfo: {
- auto object = item.as<MethodInfo>();
+ const auto object = item.as<MethodInfo>();
if (object && object->semanticScope()) {
std::optional<QQmlJSScope::ConstPtr> scope = object->semanticScope();
if (!scope)
return {};
- if (QQmlJSScope::ConstPtr targetScope =
+ if (const QQmlJSScope::ConstPtr targetScope =
findScopeOfSpecialItems(scope.value()->parentScope(), item)) {
const auto signalOrProperty = resolveNameInQmlScope(object->name, targetScope);
if (!signalOrProperty)
@@ -1560,10 +1538,10 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{ object->name,
- findDefiningScopeForMethod(
- targetScope, signalOrProperty->name),
- signalOrProperty->type };
+ return ExpressionType{ object->name,
+ findDefiningScopeForMethod(targetScope,
+ signalOrProperty->name),
+ signalOrProperty->type };
case ResolveActualTypeForFieldMemberExpression:
// not supported for methods
return {};
@@ -1575,8 +1553,8 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
if (scope.value()->scopeType() == QQmlJSScope::ScopeType::JSFunctionScope)
scope = scope.value()->parentScope();
- if (auto result = resolveSignalOrPropertyExpressionType(object->name, scope.value(),
- options)) {
+ if (const auto result = resolveSignalOrPropertyExpressionType(
+ object->name, scope.value(), options)) {
return result;
}
qDebug(QQmlLSUtilsLog) << "QQmlLSUtils::resolveExpressionType() could not resolve the"
@@ -1597,13 +1575,13 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
*/
const auto scope = item.qmlObject().semanticScope();
const auto name = item.field(Fields::value).value().toString();
- if (QQmlJSScope::ConstPtr targetScope = findScopeOfSpecialItems(scope, item)) {
+ if (const QQmlJSScope::ConstPtr targetScope = findScopeOfSpecialItems(scope, item)) {
const auto signalOrProperty = resolveNameInQmlScope(name, targetScope);
if (!signalOrProperty)
return {};
switch (options) {
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
+ return ExpressionType{
name, findDefiningScopeForProperty(targetScope, signalOrProperty->name),
signalOrProperty->type
};
@@ -1617,32 +1595,36 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
}
case DomType::EnumItem: {
const QString enumValue = item.field(Fields::name).value().toString();
- QQmlJSScope::ConstPtr referrerScope = item.rootQmlObject(GoTo::MostLikely).semanticScope();
- if (!referrerScope->hasEnumerationKey(enumValue))
- return {};
- switch (options) {
- // special case: use the owner's scope here, as enums do not have their own
- // QQmlJSScope.
- case ResolveActualTypeForFieldMemberExpression:
- case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
- enumValue, findDefiningScopeForEnumerationKey(referrerScope, enumValue),
- EnumeratorValueIdentifier
- };
+ const QQmlJSScope::ConstPtr referrerScope
+ = item.rootQmlObject(GoTo::MostLikely).semanticScope();
+ if (!referrerScope->hasEnumerationKey(enumValue))
+ return {};
+ switch (options) {
+ // special case: use the owner's scope here, as enums do not have their own
+ // QQmlJSScope.
+ case ResolveActualTypeForFieldMemberExpression:
+ case ResolveOwnerType:
+ return ExpressionType {
+ enumValue,
+ findDefiningScopeForEnumerationKey(referrerScope, enumValue),
+ EnumeratorValueIdentifier
+ };
}
Q_UNREACHABLE_RETURN({});
}
case DomType::EnumDecl: {
const QString enumName = item.field(Fields::name).value().toString();
- QQmlJSScope::ConstPtr referrerScope = item.rootQmlObject(GoTo::MostLikely).semanticScope();
+ const QQmlJSScope::ConstPtr referrerScope
+ = item.rootQmlObject(GoTo::MostLikely).semanticScope();
if (!referrerScope->hasEnumeration(enumName))
return {};
switch (options) {
// special case: use the owner's scope here, as enums do not have their own QQmlJSScope.
case ResolveActualTypeForFieldMemberExpression:
case ResolveOwnerType:
- return QQmlLSUtilsExpressionType{
- enumName, findDefiningScopeForEnumeration(referrerScope, enumName),
+ return ExpressionType {
+ enumName,
+ findDefiningScopeForEnumeration(referrerScope, enumName),
EnumeratorIdentifier
};
}
@@ -1658,8 +1640,7 @@ QQmlLSUtils::resolveExpressionType(const QQmlJS::Dom::DomItem &item,
Q_UNREACHABLE();
}
-DomItem QQmlLSUtils::sourceLocationToDomItem(const DomItem &file,
- const QQmlJS::SourceLocation &location)
+DomItem sourceLocationToDomItem(const DomItem &file, const QQmlJS::SourceLocation &location)
{
// QQmlJS::SourceLocation starts counting at 1 but the utils and the LSP start at 0.
auto items = QQmlLSUtils::itemsFromTextLocation(file, location.startLine - 1,
@@ -1694,7 +1675,7 @@ DomItem QQmlLSUtils::sourceLocationToDomItem(const DomItem &file,
return {};
}
-static std::optional<QQmlLSUtilsLocation>
+static std::optional<Location>
findMethodDefinitionOf(const DomItem &file, QQmlJS::SourceLocation location, const QString &name)
{
DomItem owner = QQmlLSUtils::sourceLocationToDomItem(file, location).qmlObject();
@@ -1706,7 +1687,7 @@ findMethodDefinitionOf(const DomItem &file, QQmlJS::SourceLocation location, con
auto regions = fileLocation->info().regions;
if (auto it = regions.constFind(IdentifierRegion); it != regions.constEnd()) {
- QQmlLSUtilsLocation result;
+ Location result;
result.sourceLocation = *it;
result.filename = method.canonicalFilePath();
return result;
@@ -1715,7 +1696,7 @@ findMethodDefinitionOf(const DomItem &file, QQmlJS::SourceLocation location, con
return {};
}
-static std::optional<QQmlLSUtilsLocation>
+static std::optional<Location>
findPropertyDefinitionOf(const DomItem &file, QQmlJS::SourceLocation propertyDefinitionLocation,
const QString &name)
{
@@ -1729,7 +1710,7 @@ findPropertyDefinitionOf(const DomItem &file, QQmlJS::SourceLocation propertyDef
auto regions = fileLocation->info().regions;
if (auto it = regions.constFind(IdentifierRegion); it != regions.constEnd()) {
- QQmlLSUtilsLocation result;
+ Location result;
result.sourceLocation = *it;
result.filename = propertyDefinition.canonicalFilePath();
return result;
@@ -1738,10 +1719,9 @@ findPropertyDefinitionOf(const DomItem &file, QQmlJS::SourceLocation propertyDef
return {};
}
-std::optional<QQmlLSUtilsLocation> QQmlLSUtils::findDefinitionOf(const DomItem &item)
+std::optional<Location> findDefinitionOf(const DomItem &item)
{
- auto resolvedExpression =
- resolveExpressionType(item, QQmlLSUtilsResolveOptions::ResolveOwnerType);
+ auto resolvedExpression = resolveExpressionType(item, ResolveOptions::ResolveOwnerType);
if (!resolvedExpression || !resolvedExpression->name || !resolvedExpression->semanticScope) {
qCDebug(QQmlLSUtilsLog) << "QQmlLSUtils::findDefinitionOf: Type could not be resolved.";
@@ -1755,7 +1735,7 @@ std::optional<QQmlLSUtilsLocation> QQmlLSUtils::findDefinitionOf(const DomItem &
.value()
.location;
- return QQmlLSUtilsLocation{ resolvedExpression->semanticScope->filePath(), location };
+ return Location{ resolvedExpression->semanticScope->filePath(), location };
}
case PropertyIdentifier: {
@@ -1789,13 +1769,13 @@ std::optional<QQmlLSUtilsLocation> QQmlLSUtils::findDefinitionOf(const DomItem &
return {};
}
- QQmlLSUtilsLocation result;
+ Location result;
result.sourceLocation = FileLocations::treeOf(domId)->info().fullRegion;
result.filename = domId.canonicalFilePath();
return result;
}
case QmlComponentIdentifier: {
- QQmlLSUtilsLocation result;
+ Location result;
result.sourceLocation = resolvedExpression->semanticScope->sourceLocation();
result.filename = resolvedExpression->semanticScope->filePath();
return result;
@@ -1850,8 +1830,7 @@ static QQmlJSScope::ConstPtr methodOwnerFrom(const QQmlJSScope::ConstPtr &type,
return typeWithDefinition;
}
-static QQmlJSScope::ConstPtr
-expressionTypeWithDefinition(const QQmlLSUtilsExpressionType &ownerType)
+static QQmlJSScope::ConstPtr expressionTypeWithDefinition(const ExpressionType &ownerType)
{
switch (ownerType.type) {
case PropertyIdentifier:
@@ -1886,53 +1865,48 @@ expressionTypeWithDefinition(const QQmlLSUtilsExpressionType &ownerType)
return {};
}
-std::optional<QQmlLSUtilsErrorMessage> QQmlLSUtils::checkNameForRename(
- const DomItem &item, const QString &dirtyNewName,
- const std::optional<QQmlLSUtilsExpressionType> &ownerType)
+std::optional<ErrorMessage> checkNameForRename(const DomItem &item, const QString &dirtyNewName,
+ const std::optional<ExpressionType> &ownerType)
{
if (!ownerType) {
- if (const auto resolved = QQmlLSUtils::resolveExpressionType(item, ResolveOwnerType))
+ if (const auto resolved = resolveExpressionType(item, ResolveOwnerType))
return checkNameForRename(item, dirtyNewName, resolved);
}
// general checks for ECMAscript identifiers
if (!isValidEcmaScriptIdentifier(dirtyNewName))
- return QQmlLSUtilsErrorMessage{ 0, u"Invalid EcmaScript identifier!"_s };
+ return ErrorMessage{ 0, u"Invalid EcmaScript identifier!"_s };
const auto userSemanticScope = item.nearestSemanticScope();
if (!ownerType || !userSemanticScope) {
- return QQmlLSUtilsErrorMessage{ 0, u"Requested item cannot be renamed"_s };
+ return ErrorMessage{ 0, u"Requested item cannot be renamed"_s };
}
// type specific checks
switch (ownerType->type) {
case PropertyChangedSignalIdentifier: {
if (!QQmlSignalNames::isChangedSignalName(dirtyNewName)) {
- return QQmlLSUtilsErrorMessage{ 0, u"Invalid name for a property changed signal."_s };
+ return ErrorMessage{ 0, u"Invalid name for a property changed signal."_s };
}
break;
}
case PropertyChangedHandlerIdentifier: {
if (!QQmlSignalNames::isChangedHandlerName(dirtyNewName)) {
- return QQmlLSUtilsErrorMessage{
- 0, u"Invalid name for a property changed handler identifier."_s
- };
+ return ErrorMessage{ 0, u"Invalid name for a property changed handler identifier."_s };
}
break;
}
case SignalHandlerIdentifier: {
if (!QQmlSignalNames::isHandlerName(dirtyNewName)) {
- return QQmlLSUtilsErrorMessage{ 0, u"Invalid name for a signal handler identifier."_s };
+ return ErrorMessage{ 0, u"Invalid name for a signal handler identifier."_s };
}
break;
}
// TODO: any other specificities?
case QmlObjectIdIdentifier:
if (dirtyNewName.front().isLetter() && !dirtyNewName.front().isLower()) {
- return QQmlLSUtilsErrorMessage{
- 0, u"Object id names cannot start with an upper case letter."_s
- };
+ return ErrorMessage{ 0, u"Object id names cannot start with an upper case letter."_s };
}
break;
case JavaScriptIdentifier:
@@ -1946,7 +1920,7 @@ std::optional<QQmlLSUtilsErrorMessage> QQmlLSUtils::checkNameForRename(
auto typeWithDefinition = expressionTypeWithDefinition(*ownerType);
if (!typeWithDefinition) {
- return QQmlLSUtilsErrorMessage{
+ return ErrorMessage{
0,
u"Renaming has not been implemented for the requested item."_s,
};
@@ -1954,16 +1928,16 @@ std::optional<QQmlLSUtilsErrorMessage> QQmlLSUtils::checkNameForRename(
// is it not defined in QML?
if (!typeWithDefinition->isComposite()) {
- return QQmlLSUtilsErrorMessage{ 0, u"Cannot rename items defined in non-QML files."_s };
+ return ErrorMessage{ 0, u"Cannot rename items defined in non-QML files."_s };
}
// is it defined in the current module?
const QString moduleOfDefinition = ownerType->semanticScope->moduleName();
const QString moduleOfCurrentItem = userSemanticScope->moduleName();
if (moduleOfDefinition != moduleOfCurrentItem) {
- return QQmlLSUtilsErrorMessage{
+ return ErrorMessage{
0,
- u"Cannot rename items defined in the %1 module fromits usage in the %2 module."_s
+ u"Cannot rename items defined in the \"%1\" module from a usage in the \"%2\" module."_s
.arg(moduleOfDefinition, moduleOfCurrentItem),
};
}
@@ -1993,8 +1967,7 @@ static std::optional<QString> oldNameFrom(const DomItem &item)
Q_UNREACHABLE_RETURN(std::nullopt);
}
-static std::optional<QString> newNameFrom(const QString &dirtyNewName,
- QQmlLSUtilsIdentifierType alternative)
+static std::optional<QString> newNameFrom(const QString &dirtyNewName, IdentifierType alternative)
{
// When renaming signal/property changed handlers and property changed signals:
// Get the actual corresponding signal name (for signal handlers) or property name (for
@@ -2035,27 +2008,26 @@ Special cases:
All of the chopping operations are done using the static helpers from QQmlSignalNames.
\endlist
*/
-QList<QQmlLSUtilsEdit> QQmlLSUtils::renameUsagesOf(
- const DomItem &item, const QString &dirtyNewName,
- const std::optional<QQmlLSUtilsExpressionType> &targetType)
+RenameUsages renameUsagesOf(const DomItem &item, const QString &dirtyNewName,
+ const std::optional<ExpressionType> &targetType)
{
- QList<QQmlLSUtilsEdit> results;
- const QList<QQmlLSUtilsLocation> locations = findUsagesOf(item);
+ RenameUsages result;
+ const Usages locations = findUsagesOf(item);
if (locations.isEmpty())
- return results;
+ return result;
auto oldName = oldNameFrom(item);
if (!oldName)
- return results;
+ return result;
QQmlJSScope::ConstPtr semanticScope;
if (targetType) {
semanticScope = targetType->semanticScope;
- } else if (const auto resolved = QQmlLSUtils::resolveExpressionType(
- item, QQmlLSUtilsResolveOptions::ResolveOwnerType)) {
+ } else if (const auto resolved =
+ QQmlLSUtils::resolveExpressionType(item, ResolveOptions::ResolveOwnerType)) {
semanticScope = resolved->semanticScope;
} else {
- return results;
+ return result;
}
QString newName;
@@ -2080,9 +2052,9 @@ QList<QQmlLSUtilsEdit> QQmlLSUtils::renameUsagesOf(
QQmlSignalNames::propertyNameToChangedHandlerName(newName);
// set the new name at the found usages, but add "on"-prefix and "Changed"-suffix if needed
- for (const auto &location : locations) {
+ for (const auto &location : locations.usagesInFile()) {
const qsizetype currentLength = location.sourceLocation.length;
- QQmlLSUtilsEdit edit;
+ Edit edit;
edit.location = location;
if (oldNameLength == currentLength) {
// normal case, nothing to do
@@ -2104,35 +2076,52 @@ QList<QQmlLSUtilsEdit> QQmlLSUtils::renameUsagesOf(
qCDebug(QQmlLSUtilsLog) << "Found usage with wrong identifier length, ignoring...";
continue;
}
- results.append(edit);
+ result.appendRename(edit);
}
- return results;
+ for (const auto &filename : locations.usagesInFilename()) {
+ // assumption: we only rename files ending in .qml or .ui.qml in qmlls
+ QString extension;
+ if (filename.endsWith(u".ui.qml"_s))
+ extension = u".ui.qml"_s;
+ else if (filename.endsWith(u".qml"_s))
+ extension = u".qml"_s;
+ else
+ continue;
+
+ QFileInfo info(filename);
+ // do not rename the file if it has a custom type name in the qmldir
+ if (!info.isFile() || info.baseName() != oldName)
+ continue;
+
+ const QString newFilename =
+ QDir::cleanPath(filename + "/.."_L1) + '/'_L1 + newName + extension;
+ result.appendRename({ filename, newFilename });
+ }
+
+ return result;
}
-QQmlLSUtilsLocation QQmlLSUtilsLocation::from(const QString &fileName, const QString &code,
- quint32 startLine, quint32 startCharacter,
- quint32 length)
+Location Location::from(const QString &fileName, const QString &code, quint32 startLine,
+ quint32 startCharacter, quint32 length)
{
quint32 offset = QQmlLSUtils::textOffsetFrom(code, startLine - 1, startCharacter - 1);
- QQmlLSUtilsLocation location{
- fileName, QQmlJS::SourceLocation{ offset, length, startLine, startCharacter }
- };
+ Location location{ fileName,
+ QQmlJS::SourceLocation{ offset, length, startLine, startCharacter } };
return location;
}
-QQmlLSUtilsEdit QQmlLSUtilsEdit::from(const QString &fileName, const QString &code,
- quint32 startLine, quint32 startCharacter, quint32 length,
- const QString &newName)
+Edit Edit::from(const QString &fileName, const QString &code, quint32 startLine,
+ quint32 startCharacter, quint32 length, const QString &newName)
{
- QQmlLSUtilsEdit rename;
- rename.location = QQmlLSUtilsLocation::from(fileName, code, startLine, startCharacter, length);
+ Edit rename;
+ rename.location = Location::from(fileName, code, startLine, startCharacter, length);
rename.replacement = newName;
return rename;
}
-bool QQmlLSUtils::isValidEcmaScriptIdentifier(QStringView identifier)
+bool isValidEcmaScriptIdentifier(QStringView identifier)
{
QQmlJS::Lexer lexer(nullptr);
lexer.setCode(identifier.toString(), 0);
@@ -2158,7 +2147,7 @@ https://doc.qt.io/qt-6/windows-building.html#step-2-install-build-requirements c
to have CMake in your path to build Qt. So a developer machine running qmlls has a high chance of
having CMake in their path, if CMake is installed and used.
*/
-QPair<QString, QStringList> QQmlLSUtils::cmakeBuildCommand(const QString &path)
+QPair<QString, QStringList> cmakeBuildCommand(const QString &path)
{
const QPair<QString, QStringList> result{
u"cmake"_s, { u"--build"_s, path, u"-t"_s, u"all_qmltyperegistrations"_s }
@@ -2166,18 +2155,32 @@ QPair<QString, QStringList> QQmlLSUtils::cmakeBuildCommand(const QString &path)
return result;
}
+void Usages::sort()
+{
+ std::sort(m_usagesInFile.begin(), m_usagesInFile.end());
+ std::sort(m_usagesInFilename.begin(), m_usagesInFilename.end());
+}
-QByteArray QQmlLSUtils::getDocumentationFromLocation(const DomItem &file, const QQmlLSUtilsTextPosition &position)
+bool Usages::isEmpty() const
{
- QByteArray result;
- const auto [line, character] = position;
- const auto itemLocation = itemsFromTextLocation(file, line, character);
+ return m_usagesInFilename.isEmpty() && m_usagesInFile.isEmpty();
+}
- // TODO:
- // Process found item's internalKind and fetch its documentation.
- Q_UNUSED(itemLocation);
+Usages::Usages(const QList<Location> &usageInFile, const QList<QString> &usageInFilename)
+ : m_usagesInFile(usageInFile), m_usagesInFilename(usageInFilename)
+{
+ std::sort(m_usagesInFile.begin(), m_usagesInFile.end());
+ std::sort(m_usagesInFilename.begin(), m_usagesInFilename.end());
+}
- return result;
+RenameUsages::RenameUsages(const QList<Edit> &renamesInFile,
+ const QList<FileRename> &renamesInFilename)
+ : m_renamesInFile(renamesInFile), m_renamesInFilename(renamesInFilename)
+{
+ std::sort(m_renamesInFile.begin(), m_renamesInFile.end());
+ std::sort(m_renamesInFilename.begin(), m_renamesInFilename.end());
}
+} // namespace QQmlLSUtils
+
QT_END_NAMESPACE
diff --git a/src/qmlls/qqmllsutils_p.h b/src/qmlls/qqmllsutils_p.h
index 0ba58f8294..84cf31c368 100644
--- a/src/qmlls/qqmllsutils_p.h
+++ b/src/qmlls/qqmllsutils_p.h
@@ -27,19 +27,21 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(QQmlLSUtilsLog);
-struct QQmlLSUtilsItemLocation
+namespace QQmlLSUtils {
+
+struct ItemLocation
{
QQmlJS::Dom::DomItem domItem;
QQmlJS::Dom::FileLocations::Tree fileLocation;
};
-struct QQmlLSUtilsTextPosition
+struct TextPosition
{
int line;
int character;
};
-enum QQmlLSUtilsIdentifierType : char {
+enum IdentifierType : char {
JavaScriptIdentifier,
PropertyIdentifier,
PropertyChangedSignalIdentifier,
@@ -56,53 +58,75 @@ enum QQmlLSUtilsIdentifierType : char {
QmlComponentIdentifier,
};
-struct QQmlLSUtilsErrorMessage
+struct ErrorMessage
{
int code;
QString message;
};
-struct QQmlLSUtilsExpressionType
+struct ExpressionType
{
std::optional<QString> name;
QQmlJSScope::ConstPtr semanticScope;
- QQmlLSUtilsIdentifierType type;
+ IdentifierType type;
};
-struct QQmlLSUtilsLocation
+struct Location
{
QString filename;
QQmlJS::SourceLocation sourceLocation;
- static QQmlLSUtilsLocation from(const QString &fileName, const QString &code, quint32 startLine,
- quint32 startCharacter, quint32 length);
+ static Location from(const QString &fileName, const QString &code, quint32 startLine,
+ quint32 startCharacter, quint32 length);
- friend bool operator<(const QQmlLSUtilsLocation &a, const QQmlLSUtilsLocation &b)
+ friend bool operator<(const Location &a, const Location &b)
{
return std::make_tuple(a.filename, a.sourceLocation.begin(), a.sourceLocation.end())
< std::make_tuple(b.filename, b.sourceLocation.begin(), b.sourceLocation.end());
}
- friend bool operator==(const QQmlLSUtilsLocation &a, const QQmlLSUtilsLocation &b)
+ friend bool operator==(const Location &a, const Location &b)
{
return std::make_tuple(a.filename, a.sourceLocation.begin(), a.sourceLocation.end())
== std::make_tuple(b.filename, b.sourceLocation.begin(), b.sourceLocation.end());
}
};
-struct QQmlLSUtilsEdit
+/*!
+Represents a rename operation where the file itself needs to be renamed.
+\internal
+*/
+struct FileRename
{
- QQmlLSUtilsLocation location;
+ QString oldFilename;
+ QString newFilename;
+
+ friend bool comparesEqual(const FileRename &a, const FileRename &b) noexcept
+ {
+ return std::tie(a.oldFilename, a.newFilename) == std::tie(b.oldFilename, b.newFilename);
+ }
+ friend Qt::strong_ordering compareThreeWay(const FileRename &a, const FileRename &b) noexcept
+ {
+ if (a.oldFilename != b.oldFilename)
+ return compareThreeWay(a.oldFilename, b.oldFilename);
+ return compareThreeWay(a.newFilename, b.newFilename);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(FileRename);
+};
+
+struct Edit
+{
+ Location location;
QString replacement;
- static QQmlLSUtilsEdit from(const QString &fileName, const QString &code, quint32 startLine,
- quint32 startCharacter, quint32 length, const QString &newName);
+ static Edit from(const QString &fileName, const QString &code, quint32 startLine,
+ quint32 startCharacter, quint32 length, const QString &newName);
- friend bool operator<(const QQmlLSUtilsEdit &a, const QQmlLSUtilsEdit &b)
+ friend bool operator<(const Edit &a, const Edit &b)
{
return std::make_tuple(a.location, a.replacement)
< std::make_tuple(b.location, b.replacement);
}
- friend bool operator==(const QQmlLSUtilsEdit &a, const QQmlLSUtilsEdit &b)
+ friend bool operator==(const Edit &a, const Edit &b)
{
return std::make_tuple(a.location, a.replacement)
== std::make_tuple(b.location, b.replacement);
@@ -110,6 +134,81 @@ struct QQmlLSUtilsEdit
};
/*!
+Represents the locations where some highlighting should take place, like in the "find all
+references" feature of the LSP. Those locations are pointing to parts of a Qml file or to a Qml
+file name.
+
+The file names are not reported as usage to the LSP and are currently only needed for the renaming
+operation to be able to rename files.
+
+\internal
+*/
+class Usages
+{
+public:
+ void sort();
+ bool isEmpty() const;
+
+ friend bool comparesEqual(const Usages &a, const Usages &b)
+ {
+ return a.m_usagesInFile == b.m_usagesInFile && a.m_usagesInFilename == b.m_usagesInFilename;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(Usages)
+
+ Usages() = default;
+ Usages(const QList<Location> &usageInFile, const QList<QString> &usageInFilename);
+
+ QList<Location> usagesInFile() const { return m_usagesInFile; };
+ QList<QString> usagesInFilename() const { return m_usagesInFilename; };
+
+ void appendUsage(const Location &edit)
+ {
+ if (!m_usagesInFile.contains(edit))
+ m_usagesInFile.append(edit);
+ };
+ void appendFilenameUsage(const QString &edit)
+ {
+
+ if (!m_usagesInFilename.contains(edit))
+ m_usagesInFilename.append(edit);
+ };
+
+private:
+ QList<Location> m_usagesInFile;
+ QList<QString> m_usagesInFilename;
+};
+
+/*!
+Represents the locations where a renaming should take place. Parts of text inside a file can be
+renamed and also filename themselves can be renamed.
+
+\internal
+*/
+class RenameUsages
+{
+public:
+ friend bool comparesEqual(const RenameUsages &a, const RenameUsages &b)
+ {
+ return std::tie(a.m_renamesInFile, a.m_renamesInFilename)
+ == std::tie(b.m_renamesInFile, b.m_renamesInFilename);
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(RenameUsages)
+
+ RenameUsages() = default;
+ RenameUsages(const QList<Edit> &renamesInFile, const QList<FileRename> &renamesInFilename);
+
+ QList<Edit> renameInFile() const { return m_renamesInFile; };
+ QList<FileRename> renameInFilename() const { return m_renamesInFilename; };
+
+ void appendRename(const Edit &edit) { m_renamesInFile.append(edit); };
+ void appendRename(const FileRename &edit) { m_renamesInFilename.append(edit); };
+
+private:
+ QList<Edit> m_renamesInFile;
+ QList<FileRename> m_renamesInFilename;
+};
+
+/*!
\internal
Choose whether to resolve the owner type or the entire type (the latter is only required to
resolve the types of qualified names and property accesses).
@@ -122,57 +221,54 @@ struct QQmlLSUtilsEdit
might lose some information about the owner. For example, resolving "x" in "myRectangle.x"
will return the JS type for float that was used to define the "x" property.
*/
-enum QQmlLSUtilsResolveOptions {
+enum ResolveOptions {
ResolveOwnerType,
ResolveActualTypeForFieldMemberExpression,
};
-enum class ImportCompletionType { None, Module, Version };
-
using DomItem = QQmlJS::Dom::DomItem;
-class QQmlLSUtils
-{
-public:
- static qsizetype textOffsetFrom(const QString &code, int row, int character);
- static QQmlLSUtilsTextPosition textRowAndColumnFrom(const QString &code, qsizetype offset);
- static QList<QQmlLSUtilsItemLocation> itemsFromTextLocation(const DomItem &file,
- int line, int character);
- static DomItem sourceLocationToDomItem(const DomItem &file,
- const QQmlJS::SourceLocation &location);
- static QByteArray lspUriToQmlUrl(const QByteArray &uri);
- static QByteArray qmlUrlToLspUri(const QByteArray &url);
- static QLspSpecification::Range qmlLocationToLspLocation(const QString &code,
- QQmlJS::SourceLocation qmlLocation);
- static DomItem baseObject(const DomItem &qmlObject);
- static std::optional<QQmlLSUtilsLocation>
- findTypeDefinitionOf(const DomItem &item);
- static std::optional<QQmlLSUtilsLocation> findDefinitionOf(const DomItem &item);
- static QList<QQmlLSUtilsLocation> findUsagesOf(const DomItem &item);
-
- static std::optional<QQmlLSUtilsErrorMessage> checkNameForRename(
- const DomItem &item, const QString &newName,
- const std::optional<QQmlLSUtilsExpressionType> &targetType = std::nullopt);
- static QList<QQmlLSUtilsEdit> renameUsagesOf(
- const DomItem &item, const QString &newName,
- const std::optional<QQmlLSUtilsExpressionType> &targetType = std::nullopt);
-
- static std::optional<QQmlLSUtilsExpressionType> resolveExpressionType(
- const DomItem &item, QQmlLSUtilsResolveOptions);
- static bool isValidEcmaScriptIdentifier(QStringView view);
-
- static QPair<QString, QStringList> cmakeBuildCommand(const QString &path);
-
- // Documentation Hints
- static QByteArray getDocumentationFromLocation(const DomItem &file, const QQmlLSUtilsTextPosition &position);
-
- static bool isFieldMemberExpression(const DomItem &item);
- static bool isFieldMemberAccess(const DomItem &item);
- static QStringList fieldMemberExpressionBits(const DomItem &item,
- const DomItem &stopAtChild = {});
-
- static QString qualifiersFrom(const DomItem &el);
-};
+qsizetype textOffsetFrom(const QString &code, int row, int character);
+TextPosition textRowAndColumnFrom(const QString &code, qsizetype offset);
+QList<ItemLocation> itemsFromTextLocation(const DomItem &file, int line, int character);
+DomItem sourceLocationToDomItem(const DomItem &file, const QQmlJS::SourceLocation &location);
+QByteArray lspUriToQmlUrl(const QByteArray &uri);
+QByteArray qmlUrlToLspUri(const QByteArray &url);
+QLspSpecification::Range qmlLocationToLspLocation(const QString &code,
+ QQmlJS::SourceLocation qmlLocation);
+DomItem baseObject(const DomItem &qmlObject);
+std::optional<Location> findTypeDefinitionOf(const DomItem &item);
+std::optional<Location> findDefinitionOf(const DomItem &item);
+Usages findUsagesOf(const DomItem &item);
+
+std::optional<ErrorMessage>
+checkNameForRename(const DomItem &item, const QString &newName,
+ const std::optional<ExpressionType> &targetType = std::nullopt);
+RenameUsages renameUsagesOf(const DomItem &item, const QString &newName,
+ const std::optional<ExpressionType> &targetType = std::nullopt);
+std::optional<ExpressionType> resolveExpressionType(const DomItem &item, ResolveOptions);
+bool isValidEcmaScriptIdentifier(QStringView view);
+
+QPair<QString, QStringList> cmakeBuildCommand(const QString &path);
+
+bool isFieldMemberExpression(const DomItem &item);
+bool isFieldMemberAccess(const DomItem &item);
+QStringList fieldMemberExpressionBits(const DomItem &item, const DomItem &stopAtChild = {});
+
+QString qualifiersFrom(const DomItem &el);
+
+QQmlJSScope::ConstPtr findDefiningScopeForProperty(const QQmlJSScope::ConstPtr &referrerScope,
+ const QString &nameToCheck);
+QQmlJSScope::ConstPtr findDefiningScopeForBinding(const QQmlJSScope::ConstPtr &referrerScope,
+ const QString &nameToCheck);
+QQmlJSScope::ConstPtr findDefiningScopeForMethod(const QQmlJSScope::ConstPtr &referrerScope,
+ const QString &nameToCheck);
+QQmlJSScope::ConstPtr findDefiningScopeForEnumeration(const QQmlJSScope::ConstPtr &referrerScope,
+ const QString &nameToCheck);
+QQmlJSScope::ConstPtr findDefiningScopeForEnumerationKey(const QQmlJSScope::ConstPtr &referrerScope,
+ const QString &nameToCheck);
+} // namespace QQmlLSUtils
+
QT_END_NAMESPACE
#endif // QLANGUAGESERVERUTILS_P_H
diff --git a/src/qmlls/qqmlrangeformatting.cpp b/src/qmlls/qqmlrangeformatting.cpp
index 1bcabc190d..fab8260d6b 100644
--- a/src/qmlls/qqmlrangeformatting.cpp
+++ b/src/qmlls/qqmlrangeformatting.cpp
@@ -14,8 +14,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(formatLog)
-
QQmlRangeFormatting::QQmlRangeFormatting(QmlLsp::QQmlCodeModel *codeModel)
: QQmlBaseModule(codeModel)
{
diff --git a/src/qmlls/qqmlrenamesymbolsupport.cpp b/src/qmlls/qqmlrenamesymbolsupport.cpp
index a812b5a25c..a1e16ad87b 100644
--- a/src/qmlls/qqmlrenamesymbolsupport.cpp
+++ b/src/qmlls/qqmlrenamesymbolsupport.cpp
@@ -39,13 +39,15 @@ void QQmlRenameSymbolSupport::process(QQmlRenameSymbolSupport::RequestPointerArg
if (guard.setErrorFrom(itemsFound))
return;
- QQmlLSUtilsItemLocation &front = std::get<QList<QQmlLSUtilsItemLocation>>(itemsFound).front();
+ QQmlLSUtils::ItemLocation &front =
+ std::get<QList<QQmlLSUtils::ItemLocation>>(itemsFound).front();
const QString newName = QString::fromUtf8(request->m_parameters.newName);
- auto expressionType = QQmlLSUtils::resolveExpressionType(front.domItem, ResolveOwnerType);
+ auto expressionType =
+ QQmlLSUtils::resolveExpressionType(front.domItem, QQmlLSUtils::ResolveOwnerType);
if (!expressionType) {
- guard.setError(QQmlLSUtilsErrorMessage{ 0, u"Cannot rename the requested object"_s });
+ guard.setError(QQmlLSUtils::ErrorMessage{ 0, u"Cannot rename the requested object"_s });
return;
}
@@ -64,7 +66,7 @@ void QQmlRenameSymbolSupport::process(QQmlRenameSymbolSupport::RequestPointerArg
QHash<QString, QString> codeCache;
- for (const auto &rename : renames) {
+ for (const auto &rename : renames.renameInFile()) {
QLspSpecification::TextEdit edit;
const QUrl uri = QUrl::fromLocalFile(rename.location.filename);
@@ -103,6 +105,15 @@ void QQmlRenameSymbolSupport::process(QQmlRenameSymbolSupport::RequestPointerArg
}
editsByFileForResult.append(editsForCurrentFile);
}
+
+ // if files need to be renamed, then do it after the text edits
+ for (const auto &rename : renames.renameInFilename()) {
+ QLspSpecification::RenameFile currentRenameFile;
+ currentRenameFile.kind = "rename";
+ currentRenameFile.oldUri = QUrl::fromLocalFile(rename.oldFilename).toEncoded();
+ currentRenameFile.newUri = QUrl::fromLocalFile(rename.newFilename).toEncoded();
+ editsByFileForResult.append(currentRenameFile);
+ }
}
QT_END_NAMESPACE
diff --git a/src/qmlls/qqmlsemantictokens.cpp b/src/qmlls/qqmlsemantictokens.cpp
index 3da56782fc..03a7168149 100644
--- a/src/qmlls/qqmlsemantictokens.cpp
+++ b/src/qmlls/qqmlsemantictokens.cpp
@@ -360,7 +360,7 @@ void HighlightingVisitor::highlightScriptLiteral(const DomItem &item)
return;
const auto regions = fLocs->info().regions;
if (std::holds_alternative<QString>(literal->literalValue())) {
- const QString value = '\"' + std::get<QString>(literal->literalValue()) + '\"';
+ const QString value = u'\"' + std::get<QString>(literal->literalValue()) + u'\"';
const auto &locs = HighlightingUtils::sourceLocationsFromMultiLineToken(
value, regions[MainRegion]);
for (const auto &loc : locs)
@@ -393,22 +393,21 @@ void HighlightingVisitor::highlightIdentifier(const DomItem &item)
void HighlightingVisitor::highlightBySemanticAnalysis(const DomItem &item, QQmlJS::SourceLocation loc)
{
const auto expression = QQmlLSUtils::resolveExpressionType(
- item, QQmlLSUtilsResolveOptions::ResolveOwnerType);
+ item, QQmlLSUtils::ResolveOptions::ResolveOwnerType);
if (!expression) {
m_highlights.addHighlight(loc, int(SemanticTokenTypes::Variable));
return;
}
switch (expression->type) {
- case QmlComponentIdentifier:
+ case QQmlLSUtils::QmlComponentIdentifier:
m_highlights.addHighlight(loc, int(SemanticTokenTypes::Type));
return;
- case JavaScriptIdentifier: {
- const auto name = expression->name;
- const auto scope = expression->semanticScope;
+ case QQmlLSUtils::JavaScriptIdentifier: {
SemanticTokenTypes tokenType = SemanticTokenTypes::Variable;
int modifier = 0;
- if (const auto jsIdentifier = scope->jsIdentifier(name.value())) {
+ if (const auto jsIdentifier
+ = expression->semanticScope->jsIdentifier(expression->name.value())) {
switch (jsIdentifier.value().kind) {
case QQmlJSScope::JavaScriptIdentifier::Parameter:
tokenType = SemanticTokenTypes::Parameter;
@@ -428,10 +427,9 @@ void HighlightingVisitor::highlightBySemanticAnalysis(const DomItem &item, QQmlJ
m_highlights.addHighlight(loc, int(tokenType), modifier);
return;
}
- case PropertyIdentifier: {
+ case QQmlLSUtils::PropertyIdentifier: {
if (const auto scope = expression->semanticScope) {
- const auto name = expression->name;
- const auto property = scope->property(name.value());
+ const auto property = scope->property(expression->name.value());
int modifier = 0;
if (!property.isWritable()) {
HighlightingUtils::addModifier(SemanticTokenModifiers::Readonly,
@@ -441,37 +439,37 @@ void HighlightingVisitor::highlightBySemanticAnalysis(const DomItem &item, QQmlJ
}
return;
}
- case PropertyChangedSignalIdentifier:
+ case QQmlLSUtils::PropertyChangedSignalIdentifier:
m_highlights.addHighlight(loc, int(SemanticTokenTypes::Method));
return;
- case PropertyChangedHandlerIdentifier:
+ case QQmlLSUtils::PropertyChangedHandlerIdentifier:
m_highlights.addHighlight(loc, int(SemanticTokenTypes::Method));
return;
- case SignalIdentifier:
+ case QQmlLSUtils::SignalIdentifier:
m_highlights.addHighlight(loc, int(SemanticTokenTypes::Method));
return;
- case SignalHandlerIdentifier:
+ case QQmlLSUtils::SignalHandlerIdentifier:
m_highlights.addHighlight(loc, int(SemanticTokenTypes::Method));
return;
- case MethodIdentifier:
+ case QQmlLSUtils::MethodIdentifier:
m_highlights.addHighlight(loc, int(SemanticTokenTypes::Method));
return;
- case QmlObjectIdIdentifier:
+ case QQmlLSUtils::QmlObjectIdIdentifier:
m_highlights.addHighlight(loc, int(SemanticTokenTypes::Variable));
return;
- case SingletonIdentifier:
+ case QQmlLSUtils::SingletonIdentifier:
m_highlights.addHighlight(loc, int(SemanticTokenTypes::Type));
return;
- case EnumeratorIdentifier:
+ case QQmlLSUtils::EnumeratorIdentifier:
m_highlights.addHighlight(loc, int(SemanticTokenTypes::Enum));
return;
- case EnumeratorValueIdentifier:
+ case QQmlLSUtils::EnumeratorValueIdentifier:
m_highlights.addHighlight(loc, int(SemanticTokenTypes::EnumMember));
return;
- case AttachedTypeIdentifier:
+ case QQmlLSUtils::AttachedTypeIdentifier:
m_highlights.addHighlight(loc, int(SemanticTokenTypes::Type));
return;
- case GroupedPropertyIdentifier:
+ case QQmlLSUtils::GroupedPropertyIdentifier:
m_highlights.addHighlight(loc, int(SemanticTokenTypes::Property));
return;
default:
@@ -730,7 +728,7 @@ QList<SemanticTokensEdit> HighlightingUtils::computeDiff(const QList<int> &oldDa
if (newStart >= newData.cbegin() && newEnd <= newData.cend() && newStart < newEnd)
edit.data.emplace(newStart, newEnd);
- return { edit };
+ return { std::move(edit) };
}
@@ -742,7 +740,7 @@ void Highlights::addHighlight(const QQmlJS::SourceLocation &loc, int tokenType,
}
if (!m_highlights.contains(loc.offset))
- m_highlights.insert(loc.offset, Token(loc, tokenType, tokenModifier));
+ m_highlights.insert(loc.offset, QT_PREPEND_NAMESPACE(Token)(loc, tokenType, tokenModifier));
}
void Highlights::addHighlight(const QMap<FileLocationRegion, QQmlJS::SourceLocation> &regions,
diff --git a/src/qmlls/qqmlsemantictokens_p.h b/src/qmlls/qqmlsemantictokens_p.h
index 34c2bbd76f..193c39baea 100644
--- a/src/qmlls/qqmlsemantictokens_p.h
+++ b/src/qmlls/qqmlsemantictokens_p.h
@@ -59,7 +59,7 @@ struct Token
int tokenModifier;
};
-using HighlightsContainer = QMap<int, Token>;
+using HighlightsContainer = QMap<int, QT_PREPEND_NAMESPACE(Token)>;
/*!
\internal
@@ -74,7 +74,6 @@ struct HighlightsRange
class Highlights
{
public:
- using HighlightsContainer = QMap<int, Token>;
void addHighlight(const QQmlJS::SourceLocation &loc, int tokenType, int tokenModifier = 0);
void addHighlight(const QMap<QQmlJS::Dom::FileLocationRegion, QQmlJS::SourceLocation> &regions,
QQmlJS::Dom::FileLocationRegion region, int tokenModifier = 0);
diff --git a/src/qmlmodels/CMakeLists.txt b/src/qmlmodels/CMakeLists.txt
index 18ae5ceeff..510143bb74 100644
--- a/src/qmlmodels/CMakeLists.txt
+++ b/src/qmlmodels/CMakeLists.txt
@@ -12,7 +12,7 @@ qt_internal_add_qml_module(QmlModels
PLUGIN_TARGET modelsplugin
CLASS_NAME QtQmlModelsPlugin
DEPENDENCIES
- QtQml.Base/auto
+ QML/1.0
SOURCES
qqmlchangeset.cpp qqmlchangeset_p.h
qqmlmodelsmodule.cpp qqmlmodelsmodule_p.h
@@ -30,7 +30,6 @@ qt_internal_add_qml_module(QmlModels
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
Qt::QmlPrivate
- GENERATE_CPP_EXPORTS
)
qt_internal_extend_target(QmlModels CONDITION QT_FEATURE_qml_itemmodel
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index e24c10b786..3df3f09336 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -31,7 +31,7 @@ namespace QV4 {
namespace Heap {
struct DelegateModelGroupFunction : FunctionObject {
- void init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg));
+ void init(ExecutionEngine *engine, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg));
QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg);
uint flag;
@@ -60,9 +60,11 @@ struct DelegateModelGroupFunction : QV4::FunctionObject
{
V4_OBJECT2(DelegateModelGroupFunction, FunctionObject)
- static Heap::DelegateModelGroupFunction *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
+ static Heap::DelegateModelGroupFunction *create(
+ QV4::ExecutionEngine *engine, uint flag,
+ QV4::ReturnedValue (*code)(QQmlDelegateModelItem *, uint, const QV4::Value &))
{
- return scope->engine()->memoryManager->allocate<DelegateModelGroupFunction>(scope, flag, code);
+ return engine->memoryManager->allocate<DelegateModelGroupFunction>(engine, flag, code);
}
static ReturnedValue virtualCall(const QV4::FunctionObject *that, const Value *thisObject, const Value *argv, int argc)
@@ -78,9 +80,11 @@ struct DelegateModelGroupFunction : QV4::FunctionObject
}
};
-void Heap::DelegateModelGroupFunction::init(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
+void Heap::DelegateModelGroupFunction::init(
+ QV4::ExecutionEngine *engine, uint flag,
+ QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::Value &arg))
{
- QV4::Heap::FunctionObject::init(scope, QStringLiteral("DelegateModelGroupFunction"));
+ QV4::Heap::FunctionObject::init(engine, QStringLiteral("DelegateModelGroupFunction"));
this->flag = flag;
this->code = code;
}
@@ -1887,12 +1891,16 @@ void QQmlDelegateModelPrivate::emitChanges()
void QQmlDelegateModel::_q_modelAboutToBeReset()
{
- auto aim = static_cast<QAbstractItemModel *>(sender());
+ Q_D(QQmlDelegateModel);
+ if (!d->m_adaptorModel.adaptsAim())
+ return;
+ auto aim = d->m_adaptorModel.aim();
auto oldRoleNames = aim->roleNames();
// this relies on the fact that modelAboutToBeReset must be followed
// by a modelReset signal before any further modelAboutToBeReset can occur
- QObject::connect(aim, &QAbstractItemModel::modelReset, this, [&, oldRoleNames](){
- auto aim = static_cast<QAbstractItemModel *>(sender());
+ QObject::connect(aim, &QAbstractItemModel::modelReset, this, [this, d, oldRoleNames, aim](){
+ if (!d->m_adaptorModel.adaptsAim() || d->m_adaptorModel.aim() != aim)
+ return;
if (oldRoleNames == aim->roleNames()) {
// if the rolenames stayed the same (most common case), then we don't have
// to throw away all the setup that we did
@@ -2187,27 +2195,27 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
s = v4Engine->newString(QStringLiteral("isUnresolved"));
QV4::ScopedFunctionObject f(scope);
- QV4::ExecutionContext *global = scope.engine->rootContext();
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, 30, QQmlDelegateModelItem::get_member)));
+ QV4::ExecutionEngine *engine = scope.engine;
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, 30, QQmlDelegateModelItem::get_member)));
p->setSetter(nullptr);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("inItems"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("inPersistedItems"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("itemsIndex"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
s = v4Engine->newString(QStringLiteral("persistedItemsIndex"));
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index)));
p->setSetter(nullptr);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
@@ -2215,14 +2223,14 @@ void QQmlDelegateModelItemMetaType::initializePrototype()
QString propertyName = QLatin1String("in") + groupNames.at(i);
propertyName.replace(2, 1, propertyName.at(2).toUpper());
s = v4Engine->newString(propertyName);
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_member)));
- p->setSetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::set_member)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, i + 1, QQmlDelegateModelItem::get_member)));
+ p->setSetter((f = QV4::DelegateModelGroupFunction::create(engine, i + 1, QQmlDelegateModelItem::set_member)));
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
for (int i = 2; i < groupNames.size(); ++i) {
const QString propertyName = groupNames.at(i) + QLatin1String("Index");
s = v4Engine->newString(propertyName);
- p->setGetter((f = QV4::DelegateModelGroupFunction::create(global, i + 1, QQmlDelegateModelItem::get_index)));
+ p->setGetter((f = QV4::DelegateModelGroupFunction::create(engine, i + 1, QQmlDelegateModelItem::get_index)));
p->setSetter(nullptr);
proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
diff --git a/src/qmlmodels/qqmldmabstractitemmodeldata_p.h b/src/qmlmodels/qqmldmabstractitemmodeldata_p.h
index e3769b6d98..2994b59730 100644
--- a/src/qmlmodels/qqmldmabstractitemmodeldata_p.h
+++ b/src/qmlmodels/qqmldmabstractitemmodeldata_p.h
@@ -188,9 +188,14 @@ public:
const QByteArray &propertyName = it.key();
QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));
- QV4::ExecutionContext *global = v4->rootContext();
- QV4::ScopedFunctionObject g(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMAbstractItemModelData::get_property));
- QV4::ScopedFunctionObject s(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMAbstractItemModelData::set_property));
+ QV4::ScopedFunctionObject g(
+ scope,
+ v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(
+ v4, propertyId, QQmlDMAbstractItemModelData::get_property));
+ QV4::ScopedFunctionObject s(
+ scope,
+ v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(
+ v4, propertyId, QQmlDMAbstractItemModelData::set_property));
p->setGetter(g);
p->setSetter(s);
proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
diff --git a/src/qmlnetwork/CMakeLists.txt b/src/qmlnetwork/CMakeLists.txt
index 2e9978703b..697219b648 100644
--- a/src/qmlnetwork/CMakeLists.txt
+++ b/src/qmlnetwork/CMakeLists.txt
@@ -14,7 +14,6 @@ qt_internal_add_qml_module(QmlNetwork
Qt::Core
Qt::Network
Qt::Qml
- GENERATE_CPP_EXPORTS
)
qt_internal_extend_target(QmlNetwork CONDITION QT_FEATURE_qml_ssl
diff --git a/src/qmlnetwork/doc/src/qtqmlnetwork-qmltypes.qdoc b/src/qmlnetwork/doc/src/qtqmlnetwork-qmltypes.qdoc
index f28ab17a3f..24ddd5317c 100644
--- a/src/qmlnetwork/doc/src/qtqmlnetwork-qmltypes.qdoc
+++ b/src/qmlnetwork/doc/src/qtqmlnetwork-qmltypes.qdoc
@@ -25,7 +25,7 @@
\list
\li \l {Qt Network}
- \li \l {Qt QML QML Types}{Base QML Types}
+ \li \l {Qt Qml QML Types}{Base QML Types}
\endlist
\noautolist
diff --git a/src/qmltest/CMakeLists.txt b/src/qmltest/CMakeLists.txt
index 51fd6648ca..f42d6cc44b 100644
--- a/src/qmltest/CMakeLists.txt
+++ b/src/qmltest/CMakeLists.txt
@@ -49,7 +49,6 @@ qt_internal_add_qml_module(QuickTest
Qt::Test
PRIVATE_MODULE_INTERFACE
Qt::TestPrivate
- GENERATE_CPP_EXPORTS
)
qt_internal_extend_target(QuickTest CONDITION QT_FEATURE_qml_debug
diff --git a/src/qmltest/doc/snippets/testApp/CMakeLists.txt b/src/qmltest/doc/snippets/testApp/CMakeLists.txt
index 71eb6bebb7..cdf7b9555e 100644
--- a/src/qmltest/doc/snippets/testApp/CMakeLists.txt
+++ b/src/qmltest/doc/snippets/testApp/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.20)
diff --git a/src/qmltest/doc/snippets/testApp/MyModule/CMakeLists.txt b/src/qmltest/doc/snippets/testApp/MyModule/CMakeLists.txt
index dbbbbd45b0..4d293c27d8 100644
--- a/src/qmltest/doc/snippets/testApp/MyModule/CMakeLists.txt
+++ b/src/qmltest/doc/snippets/testApp/MyModule/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.20)
diff --git a/src/qmltest/doc/snippets/testApp/tests/CMakeLists.txt b/src/qmltest/doc/snippets/testApp/tests/CMakeLists.txt
index 3255a919f2..5533403bdc 100644
--- a/src/qmltest/doc/snippets/testApp/tests/CMakeLists.txt
+++ b/src/qmltest/doc/snippets/testApp/tests/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.2)
diff --git a/src/qmltest/doc/snippets/testApp/tests/main.cpp b/src/qmltest/doc/snippets/testApp/tests/main.cpp
index d9f1cd68ed..cf68ddb5de 100644
--- a/src/qmltest/doc/snippets/testApp/tests/main.cpp
+++ b/src/qmltest/doc/snippets/testApp/tests/main.cpp
@@ -1,5 +1,5 @@
// # Copyright (C) 2023 The Qt Company Ltd.
-// # SPDX-License-Identifier: BSD-3-Clause
+// # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [main]
#include <QtQuickTest/quicktest.h>
diff --git a/src/qmltest/doc/snippets/testApp/tests/setup.cpp b/src/qmltest/doc/snippets/testApp/tests/setup.cpp
index 92ef206e26..4ecac48d35 100644
--- a/src/qmltest/doc/snippets/testApp/tests/setup.cpp
+++ b/src/qmltest/doc/snippets/testApp/tests/setup.cpp
@@ -1,5 +1,5 @@
// # Copyright (C) 2023 The Qt Company Ltd.
-// # SPDX-License-Identifier: BSD-3-Clause
+// # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [setup]
#include "setup.h"
diff --git a/src/qmltest/doc/snippets/testApp/tests/setup.h b/src/qmltest/doc/snippets/testApp/tests/setup.h
index b6c5248667..ea6a699f2f 100644
--- a/src/qmltest/doc/snippets/testApp/tests/setup.h
+++ b/src/qmltest/doc/snippets/testApp/tests/setup.h
@@ -1,5 +1,5 @@
// # Copyright (C) 2023 The Qt Company Ltd.
-// # SPDX-License-Identifier: BSD-3-Clause
+// # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [setup]
#ifndef SETUP_H
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
index ce29dadb47..1a580f8c69 100644
--- a/src/qmltest/quicktest.cpp
+++ b/src/qmltest/quicktest.cpp
@@ -32,6 +32,8 @@
#include <QtGui/qtextdocument.h>
#include <stdio.h>
#include <QtGui/QGuiApplication>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformintegration.h>
#include <QtCore/QTranslator>
#include <QtTest/QSignalSpy>
#include <QtQml/QQmlFileSelector>
@@ -658,10 +660,12 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch
qWarning().nospace()
<< "Test '" << QDir::toNativeSeparators(path) << "' window not exposed after show().";
}
- view.requestActivate();
- if (!QTest::qWaitForWindowActive(&view)) {
- qWarning().nospace()
- << "Test '" << QDir::toNativeSeparators(path) << "' window not active after requestActivate().";
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)) {
+ view.requestActivate();
+ if (!QTest::qWaitForWindowActive(&view)) {
+ qWarning().nospace()
+ << "Test '" << QDir::toNativeSeparators(path) << "' window not active after requestActivate().";
+ }
}
if (view.isExposed()) {
// Defer property update until event loop has started
diff --git a/src/qmltoolingsettings/CMakeLists.txt b/src/qmltoolingsettings/CMakeLists.txt
index 8776a6dd98..f5e456cd96 100644
--- a/src/qmltoolingsettings/CMakeLists.txt
+++ b/src/qmltoolingsettings/CMakeLists.txt
@@ -12,5 +12,4 @@ qt_internal_add_module(QmlToolingSettingsPrivate
qqmltoolingutils.cpp
PUBLIC_LIBRARIES
Qt::Core
- GENERATE_CPP_EXPORTS
)
diff --git a/src/qmltoolingsettings/qqmltoolingsettings.cpp b/src/qmltoolingsettings/qqmltoolingsettings.cpp
index 5f8b92a8d2..bb87799915 100644
--- a/src/qmltoolingsettings/qqmltoolingsettings.cpp
+++ b/src/qmltoolingsettings/qqmltoolingsettings.cpp
@@ -123,12 +123,12 @@ bool QQmlToolingSettings::search(const QString &path)
return false;
}
-QVariant QQmlToolingSettings::value(QString name) const
+QVariant QQmlToolingSettings::value(const QString &name) const
{
return m_values.value(name);
}
-bool QQmlToolingSettings::isSet(QString name) const
+bool QQmlToolingSettings::isSet(const QString &name) const
{
if (!m_values.contains(name))
return false;
diff --git a/src/qmltoolingsettings/qqmltoolingsettings_p.h b/src/qmltoolingsettings/qqmltoolingsettings_p.h
index 555f6dec79..2ceab4727b 100644
--- a/src/qmltoolingsettings/qqmltoolingsettings_p.h
+++ b/src/qmltoolingsettings/qqmltoolingsettings_p.h
@@ -31,8 +31,8 @@ public:
bool writeDefaults() const;
bool search(const QString &path);
- QVariant value(QString name) const;
- bool isSet(QString name) const;
+ QVariant value(const QString &name) const;
+ bool isSet(const QString &name) const;
private:
QString m_toolName;
diff --git a/src/qmltyperegistrar/CMakeLists.txt b/src/qmltyperegistrar/CMakeLists.txt
index 7b17e8ddba..e1f2b48719 100644
--- a/src/qmltyperegistrar/CMakeLists.txt
+++ b/src/qmltyperegistrar/CMakeLists.txt
@@ -24,7 +24,6 @@ qt_internal_add_module(QmlTypeRegistrarPrivate
QT_NO_CAST_TO_ASCII
PUBLIC_LIBRARIES
Qt::CorePrivate
- GENERATE_CPP_EXPORTS
)
qt_internal_add_resource(QmlTypeRegistrarPrivate "jsRootMetaTypes"
diff --git a/src/qmltyperegistrar/jsroot_metatypes.json b/src/qmltyperegistrar/jsroot_metatypes.json
index 768d5f78b2..1eef336416 100644
--- a/src/qmltyperegistrar/jsroot_metatypes.json
+++ b/src/qmltyperegistrar/jsroot_metatypes.json
@@ -6072,6 +6072,10 @@
"type": "number"
},
{
+ "name": "AA_DontUseNativeMenuWindows",
+ "type": "number"
+ },
+ {
"name": "AA_SynthesizeTouchForUnhandledMouseEvents",
"type": "number"
},
@@ -6152,10 +6156,6 @@
"type": "number"
},
{
- "name": "AA_DontUseNativeMenuWindows",
- "type": "number"
- },
- {
"name": "AA_AttributeCount",
"type": "number"
},
@@ -8808,6 +8808,14 @@
"type": "number"
},
{
+ "name": "Press",
+ "type": "number"
+ },
+ {
+ "name": "Release",
+ "type": "number"
+ },
+ {
"name": "ImEnabled",
"type": "number"
},
@@ -9540,18 +9548,16 @@
{
"access": "public",
"arguments": [
- {
- }
],
"isJavaScriptFunction": true,
- "name": "sort"
+ "name": "valueOf"
},
{
"access": "public",
"arguments": [
],
"isJavaScriptFunction": true,
- "name": "valueOf"
+ "name": "shift"
}
],
"object": true,
diff --git a/src/qmltyperegistrar/qmetatypesjsonprocessor.cpp b/src/qmltyperegistrar/qmetatypesjsonprocessor.cpp
index 480d4ba187..8101b727b9 100644
--- a/src/qmltyperegistrar/qmetatypesjsonprocessor.cpp
+++ b/src/qmltyperegistrar/qmetatypesjsonprocessor.cpp
@@ -152,6 +152,7 @@ void MetaTypesJsonProcessor::postProcessForeignTypes()
{
sortTypes(m_foreignTypes);
sortStringList(&m_primitiveTypes);
+ sortStringList(&m_usingDeclarations);
addRelatedTypes();
sortStringList(&m_referencedTypes);
sortStringList(&m_includes);
@@ -227,8 +228,9 @@ MetaTypesJsonProcessor::PreProcessResult MetaTypesJsonProcessor::preProcess(
// and is not the root object, then it's foreign type has no entry of its own.
// In that case we need to generate a "primitive" entry.
- QList<QAnyStringView> aliases;
- QAnyStringView foreign;
+ QList<QAnyStringView> primitiveAliases;
+ UsingDeclaration usingDeclaration;
+
RegistrationMode mode = NoRegistration;
bool isSelfExtendingValueType = false;
bool hasJavaScriptExtension = false;
@@ -237,9 +239,9 @@ MetaTypesJsonProcessor::PreProcessResult MetaTypesJsonProcessor::preProcess(
for (const ClassInfo &classInfo : classDef.classInfos()) {
if (classInfo.name == S_FOREIGN)
- foreign = classInfo.value;
+ usingDeclaration.alias = classInfo.value;
else if (classInfo.name == S_PRIMITIVE_ALIAS)
- aliases.append(classInfo.value);
+ primitiveAliases.append(classInfo.value);
else if (classInfo.name == S_EXTENSION_IS_JAVA_SCRIPT)
hasJavaScriptExtension = (classInfo.value == S_TRUE);
else if (classInfo.name == S_EXTENDED && classDef.kind() == MetaType::Kind::Gadget)
@@ -248,6 +250,8 @@ MetaTypesJsonProcessor::PreProcessResult MetaTypesJsonProcessor::preProcess(
isRootObject = (classInfo.value == S_TRUE);
else if (classInfo.name == S_SEQUENCE)
isSequence = true;
+ else if (classInfo.name == S_USING)
+ usingDeclaration.original = classInfo.value;
else if (populateMode == PopulateMode::Yes && classInfo.name == S_ELEMENT) {
switch (classDef.kind()) {
case MetaType::Kind::Object:
@@ -270,9 +274,10 @@ MetaTypesJsonProcessor::PreProcessResult MetaTypesJsonProcessor::preProcess(
}
return PreProcessResult {
- aliases,
+ std::move(primitiveAliases),
+ usingDeclaration,
(!isRootObject && (isSequence || isSelfExtendingValueType || hasJavaScriptExtension))
- ? foreign
+ ? usingDeclaration.alias
: QAnyStringView(),
mode
};
@@ -353,10 +358,13 @@ void MetaTypesJsonProcessor::addRelatedTypes()
addRelatedType(foreignType);
seenQmlPrefix = true;
}
- if (name == S_FOREIGN) {
- const QAnyStringView foreign = obj.value;
- if (!addRelatedName(foreign, namespaces(foreignType)))
- unresolvedForeignNames.insert(foreign);
+ if (name == S_FOREIGN
+ || name == S_EXTENDED
+ || name == S_ATTACHED
+ || name == S_SEQUENCE) {
+ ResolvedTypeAlias foreign(obj.value, m_usingDeclarations);
+ if (!addRelatedName(foreign.type, namespaces(foreignType)))
+ unresolvedForeignNames.insert(foreign.type);
break;
}
}
@@ -517,7 +525,7 @@ void MetaTypesJsonProcessor::addRelatedTypes()
const auto addProperties = [&](const MetaType &context,
const QList<QAnyStringView> &namespaces) {
for (const Property &property : context.properties()) {
- ResolvedTypeAlias resolved(property.type);
+ ResolvedTypeAlias resolved(property.type, m_usingDeclarations);
if (!resolved.type.isEmpty())
addType(context, resolved.type, namespaces, "property");
}
@@ -529,12 +537,12 @@ void MetaTypesJsonProcessor::addRelatedTypes()
: {context.methods(), context.constructors(), context.sigs() }) {
for (const Method &methodObject : methods) {
for (const Argument &argument : std::as_const(methodObject.arguments)) {
- ResolvedTypeAlias resolved(argument.type);
+ ResolvedTypeAlias resolved(argument.type, m_usingDeclarations);
if (!resolved.type.isEmpty())
addType(context, resolved.type, namespaces, "argument");
}
- ResolvedTypeAlias resolved(methodObject.returnType);
+ ResolvedTypeAlias resolved(methodObject.returnType, m_usingDeclarations);
if (!resolved.type.isEmpty())
addType(context, resolved.type, namespaces, "return");
}
@@ -544,7 +552,7 @@ void MetaTypesJsonProcessor::addRelatedTypes()
const auto addEnums = [&](const MetaType &context,
const QList<QAnyStringView> &namespaces) {
for (const Enum &enumerator : context.enums()) {
- ResolvedTypeAlias resolved(enumerator.type);
+ ResolvedTypeAlias resolved(enumerator.type, m_usingDeclarations);
if (!resolved.type.isEmpty())
addType(context, resolved.type, namespaces, "enum");
}
@@ -557,7 +565,7 @@ void MetaTypesJsonProcessor::addRelatedTypes()
addType(classDef, obj.value, namespaces, "attached");
return true;
} else if (objNameValue == S_SEQUENCE) {
- ResolvedTypeAlias value(obj.value);
+ ResolvedTypeAlias value(obj.value, m_usingDeclarations);
addType(classDef, value.type, namespaces, "sequence value");
return true;
} else if (objNameValue == S_EXTENDED) {
@@ -675,6 +683,9 @@ void MetaTypesJsonProcessor::processTypes(const QCborMap &types)
m_primitiveTypes.emplaceBack(preprocessed.foreignPrimitive);
m_primitiveTypes.append(preprocessed.primitiveAliases);
}
+
+ if (preprocessed.usingDeclaration.isValid())
+ m_usingDeclarations.append(preprocessed.usingDeclaration);
}
}
@@ -691,6 +702,9 @@ void MetaTypesJsonProcessor::processForeignTypes(const QCborMap &types)
m_primitiveTypes.emplaceBack(preprocessed.foreignPrimitive);
m_primitiveTypes.append(preprocessed.primitiveAliases);
}
+
+ if (preprocessed.usingDeclaration.isValid())
+ m_usingDeclarations.append(preprocessed.usingDeclaration);
}
}
@@ -815,7 +829,7 @@ MetaTypePrivate::MetaTypePrivate(const QCborMap &cbor, const QString &inputFile)
for (const QCborValue &property : cborProperties)
properties.emplace_back(property.toMap());
- for (const QCborArray &cborMethods : { cbor[S_METHODS].toArray(), cbor[S_SLOTS].toArray() }) {
+ for (const QCborArray &cborMethods : { cbor[S_SLOTS].toArray(), cbor[S_METHODS].toArray() }) {
for (const QCborValue &method : cborMethods)
methods.emplace_back(method.toMap(), false);
}
diff --git a/src/qmltyperegistrar/qmetatypesjsonprocessor_p.h b/src/qmltyperegistrar/qmetatypesjsonprocessor_p.h
index 9d86665c52..f582cf7a1e 100644
--- a/src/qmltyperegistrar/qmetatypesjsonprocessor_p.h
+++ b/src/qmltyperegistrar/qmetatypesjsonprocessor_p.h
@@ -209,6 +209,27 @@ private:
const MetaTypePrivate *d = &s_empty;
};
+struct UsingDeclaration {
+ QAnyStringView alias;
+ QAnyStringView original;
+
+ bool isValid() const { return !alias.isEmpty() && !original.isEmpty(); }
+private:
+ friend bool comparesEqual(const UsingDeclaration &a, const UsingDeclaration &b) noexcept
+ {
+ return std::tie(a.alias, a.original) == std::tie(b.alias, b.original);
+ }
+
+ friend Qt::strong_ordering compareThreeWay(
+ const UsingDeclaration &a, const UsingDeclaration &b) noexcept
+ {
+ return a.alias != b.alias
+ ? compareThreeWay(a.alias, b.alias)
+ : compareThreeWay(a.original, b.original);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(UsingDeclaration);
+};
+
class MetaTypesJsonProcessor
{
public:
@@ -227,6 +248,7 @@ public:
QVector<MetaType> types() const { return m_types; }
QVector<MetaType> foreignTypes() const { return m_foreignTypes; }
QList<QAnyStringView> referencedTypes() const { return m_referencedTypes; }
+ QList<UsingDeclaration> usingDeclarations() const { return m_usingDeclarations; }
QList<QString> includes() const { return m_includes; }
QString extractRegisteredTypes() const;
@@ -241,15 +263,11 @@ private:
struct PreProcessResult {
QList<QAnyStringView> primitiveAliases;
+ UsingDeclaration usingDeclaration;
QAnyStringView foreignPrimitive;
RegistrationMode mode;
};
- struct PotentialPrimitiveType {
- QAnyStringView name;
- QString file;
- };
-
enum class PopulateMode { No, Yes };
static PreProcessResult preProcess(const MetaType &classDef, PopulateMode populateMode);
void addRelatedTypes();
@@ -267,6 +285,7 @@ private:
QList<QString> m_includes;
QList<QAnyStringView> m_referencedTypes;
QList<QAnyStringView> m_primitiveTypes;
+ QList<UsingDeclaration> m_usingDeclarations;
QVector<MetaType> m_types;
QVector<MetaType> m_foreignTypes;
bool m_privateIncludes = false;
diff --git a/src/qmltyperegistrar/qqmltyperegistrar.cpp b/src/qmltyperegistrar/qqmltyperegistrar.cpp
index 058a3180b0..20b3132e76 100644
--- a/src/qmltyperegistrar/qqmltyperegistrar.cpp
+++ b/src/qmltyperegistrar/qqmltyperegistrar.cpp
@@ -229,6 +229,9 @@ void QmlTypeRegistrar::write(QTextStream &output, QAnyStringView outFileName) co
.arg(majorVersion);
}
+ output << uR"(
+ QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED)"_s;
+
QVector<QAnyStringView> typesRegisteredAnonymously;
const auto fillTypesRegisteredAnonymously = [&](const auto &members, QAnyStringView typeName) {
@@ -323,18 +326,18 @@ void QmlTypeRegistrar::write(QTextStream &output, QAnyStringView outFileName) co
// We want all related metatypes to be registered by name, so that we can look them up
// without including the C++ headers. That's the reason for the QMetaType(foo).id() calls.
+ const QList<QAnyStringView> namespaces
+ = MetaTypesJsonProcessor::namespaces(classDef);
+
+ const FoundType target = QmlTypesClassDescription::findType(
+ m_types, m_foreignTypes, targetName, namespaces);
+
if (targetIsNamespace) {
// We need to figure out if the _target_ is a namespace. If not, it already has a
// QMetaType and we don't need to generate one.
QString targetTypeName = targetName;
- const QList<QAnyStringView> namespaces
- = MetaTypesJsonProcessor::namespaces(classDef);
-
- const FoundType target = QmlTypesClassDescription::findType(
- m_types, m_foreignTypes, targetName, namespaces);
-
if (!target.javaScript.isEmpty() && target.native.isEmpty())
warning(target.javaScript) << "JavaScript type cannot be used as namespace";
@@ -446,11 +449,27 @@ void QmlTypeRegistrar::write(QTextStream &output, QAnyStringView outFileName) co
}
} else {
Q_ASSERT(!className.isEmpty());
+
+ // Since we don't have a QML name for this type, it can't refer to another type.
+ Q_ASSERT(className == targetName);
+
output << uR"(
QMetaType::fromType<%1%2>().id();)"_s.arg(
className, classDef.kind() == MetaType::Kind::Object ? u" *" : u"");
}
}
+
+ const auto enums = target.native.enums();
+ for (const auto &enumerator : enums) {
+ output << uR"(
+ QMetaType::fromType<%1::%2>().id();)"_s.arg(
+ targetName, enumerator.name.toString());
+ if (!enumerator.alias.isEmpty()) {
+ output << uR"(
+ QMetaType::fromType<%1::%2>().id();)"_s.arg(
+ targetName, enumerator.alias.toString());
+ }
+ }
}
for (const auto [qmlName, exportsForSameQmlName] : qmlElementInfos.asKeyValueRange()) {
@@ -485,6 +504,7 @@ void QmlTypeRegistrar::write(QTextStream &output, QAnyStringView outFileName) co
}
output << uR"(
+ QT_WARNING_POP
qmlRegisterModule("%1", %2, %3);
}
@@ -504,6 +524,7 @@ bool QmlTypeRegistrar::generatePluginTypes(const QString &pluginTypesFile)
creator.setOwnTypes(m_types);
creator.setForeignTypes(m_foreignTypes);
creator.setReferencedTypes(m_referencedTypes);
+ creator.setUsingDeclarations(m_usingDeclarations);
creator.setModule(m_module.toUtf8());
creator.setVersion(QTypeRevision::fromVersion(m_moduleVersion.majorVersion(), 0));
@@ -539,4 +560,9 @@ void QmlTypeRegistrar::setReferencedTypes(const QList<QAnyStringView> &reference
m_referencedTypes = referencedTypes;
}
+void QmlTypeRegistrar::setUsingDeclarations(const QList<UsingDeclaration> &usingDeclarations)
+{
+ m_usingDeclarations = usingDeclarations;
+}
+
QT_END_NAMESPACE
diff --git a/src/qmltyperegistrar/qqmltyperegistrar_p.h b/src/qmltyperegistrar/qqmltyperegistrar_p.h
index e0811f2ade..fdfbe15ab7 100644
--- a/src/qmltyperegistrar/qqmltyperegistrar_p.h
+++ b/src/qmltyperegistrar/qqmltyperegistrar_p.h
@@ -35,6 +35,7 @@ class QmlTypeRegistrar
QVector<MetaType> m_types;
QVector<MetaType> m_foreignTypes;
QList<QAnyStringView> m_referencedTypes;
+ QList<UsingDeclaration> m_usingDeclarations;
MetaType findType(QAnyStringView name) const;
MetaType findTypeForeign(QAnyStringView name) const;
@@ -48,6 +49,7 @@ public:
void setIncludes(const QList<QString> &includes);
void setTypes(const QVector<MetaType> &types, const QVector<MetaType> &foreignTypes);
void setReferencedTypes(const QList<QAnyStringView> &referencedTypes);
+ void setUsingDeclarations(const QList<UsingDeclaration> &usingDeclarations);
static bool argumentsFromCommandLineAndFile(QStringList &allArguments,
const QStringList &arguments);
diff --git a/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h b/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h
index 465cc23532..fbb83b1667 100644
--- a/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h
+++ b/src/qmltyperegistrar/qqmltyperegistrarconstants_p.h
@@ -44,7 +44,8 @@ static constexpr QLatin1StringView S_IMMEDIATE_NAMES { "immediateNa
static constexpr QLatin1StringView S_INDEX { "index" };
static constexpr QLatin1StringView S_INTERFACES { "interfaces" };
static constexpr QLatin1StringView S_IS_CLONED { "isCloned" };
-static constexpr QLatin1StringView S_IS_CONSTANT { "isConstant" };
+static constexpr QLatin1StringView S_IS_TYPE_CONSTANT { "isTypeConstant" };
+static constexpr QLatin1StringView S_IS_PROPERTY_CONSTANT { "isPropertyConstant" };
static constexpr QLatin1StringView S_IS_CONSTRUCTOR { "isConstructor" };
static constexpr QLatin1StringView S_IS_CREATABLE { "isCreatable" };
static constexpr QLatin1StringView S_IS_FINAL { "isFinal" };
@@ -163,6 +164,7 @@ static constexpr QLatin1StringView S_ROOT { "QML.Root" }
static constexpr QLatin1StringView S_SEQUENCE { "QML.Sequence" };
static constexpr QLatin1StringView S_SINGLETON { "QML.Singleton" };
static constexpr QLatin1StringView S_UNCREATABLE_REASON { "QML.UncreatableReason" };
+static constexpr QLatin1StringView S_USING { "QML.Using" };
} // namespace Qml
} // namespace MetatypesJson
diff --git a/src/qmltyperegistrar/qqmltypesclassdescription.cpp b/src/qmltyperegistrar/qqmltypesclassdescription.cpp
index 7c42052a70..bbb1b25f9b 100644
--- a/src/qmltyperegistrar/qqmltypesclassdescription.cpp
+++ b/src/qmltyperegistrar/qqmltypesclassdescription.cpp
@@ -457,48 +457,99 @@ FoundType QmlTypesClassDescription::collectRelated(
return FoundType();
}
+struct UsingCompare {
+ bool operator()(const UsingDeclaration &a, QAnyStringView b) const
+ {
+ return a.alias < b;
+ }
-ResolvedTypeAlias::ResolvedTypeAlias(QAnyStringView alias)
+ bool operator()(QAnyStringView a, const UsingDeclaration &b) const
+ {
+ return a < b.alias;
+ }
+};
+
+ResolvedTypeAlias::ResolvedTypeAlias(
+ QAnyStringView alias, const QList<UsingDeclaration> &usingDeclarations)
: type(alias)
{
+ handleVoid();
if (type.isEmpty())
return;
- if (type == "void") {
- type = "";
- return;
+ handleList();
+
+ if (!isList) {
+ handlePointer();
+ handleConst();
+ }
+
+ while (true) {
+ const auto usingDeclaration = std::equal_range(
+ usingDeclarations.begin(), usingDeclarations.end(), type, UsingCompare());
+ if (usingDeclaration.first == usingDeclaration.second)
+ break;
+
+ type = usingDeclaration.first->original;
+ handleVoid();
+ if (type.isEmpty())
+ return;
+
+ if (isPointer) {
+ handleConst();
+ continue;
+ }
+
+ if (!isList) {
+ handleList();
+ if (!isList) {
+ handlePointer();
+ handleConst();
+ }
+ }
}
+}
- // This is a best effort approach and will not return correct results in the
- // presence of typedefs.
+void ResolvedTypeAlias::handleVoid()
+{
+ if (type == "void")
+ type = "";
+}
- auto handleList = [&](QLatin1StringView list) {
+void ResolvedTypeAlias::handleList()
+{
+ for (QLatin1StringView list : {"QQmlListProperty<"_L1, "QList<"_L1}) {
if (!startsWith(type, list) || type.back() != '>'_L1)
- return false;
+ continue;
const int listSize = list.size();
const QAnyStringView elementType = trimmed(type.mid(listSize, type.size() - listSize - 1));
- // QQmlListProperty internally constructs the pointer. Passing an explicit '*' will
- // produce double pointers. QList is only for value types. We can't handle QLists
- // of pointers (unless specially registered, but then they're not isList).
+ // QQmlListProperty internally constructs the pointer. Passing an explicit '*' will
+ // produce double pointers. QList is only for value types. We can't handle QLists
+ // of pointers (unless specially registered, but then they're not isList).
if (elementType.back() == '*'_L1)
- return false;
+ continue;
isList = true;
type = elementType;
- return true;
- };
+ return;
+ }
+}
- if (!handleList("QQmlListProperty<"_L1) && !handleList("QList<"_L1)) {
- if (type.back() == '*'_L1) {
- isPointer = true;
- type = type.chopped(1);
- }
- if (startsWith(type, "const "_L1)) {
- isConstant = true;
- type = type.sliced(strlen("const "));
- }
+void ResolvedTypeAlias::handlePointer()
+{
+ if (type.back() == '*'_L1) {
+ isPointer = true;
+ type = type.chopped(1);
+ }
+}
+
+void ResolvedTypeAlias::handleConst()
+{
+ if (startsWith(type, "const "_L1)) {
+ isConstant = true;
+ type = type.sliced(strlen("const "));
}
}
diff --git a/src/qmltyperegistrar/qqmltypesclassdescription_p.h b/src/qmltyperegistrar/qqmltypesclassdescription_p.h
index 60aafb948f..b48a0670da 100644
--- a/src/qmltyperegistrar/qqmltypesclassdescription_p.h
+++ b/src/qmltyperegistrar/qqmltypesclassdescription_p.h
@@ -113,12 +113,18 @@ private:
struct ResolvedTypeAlias
{
- ResolvedTypeAlias(QAnyStringView alias);
+ ResolvedTypeAlias(QAnyStringView alias, const QList<UsingDeclaration> &usingDeclarations);
QAnyStringView type;
bool isList = false;
bool isPointer = false;
bool isConstant = false;
+
+private:
+ void handleVoid();
+ void handleList();
+ void handlePointer();
+ void handleConst();
};
QT_END_NAMESPACE
diff --git a/src/qmltyperegistrar/qqmltypescreator.cpp b/src/qmltyperegistrar/qqmltypescreator.cpp
index 297a23679a..e34466c5ec 100644
--- a/src/qmltyperegistrar/qqmltypescreator.cpp
+++ b/src/qmltyperegistrar/qqmltypescreator.cpp
@@ -144,7 +144,9 @@ void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &colle
exportStrings.append(QUtf8StringView(entry));
m_qml.writeStringListBinding(S_EXPORTS, exportStrings);
- m_qml.writeBooleanBinding(S_IS_CREATABLE, collector.isCreatable && !collector.isSingleton);
+
+ if (!collector.isCreatable || collector.isSingleton)
+ m_qml.writeBooleanBinding(S_IS_CREATABLE, false);
if (collector.isStructured)
m_qml.writeBooleanBinding(S_IS_STRUCTURED, true);
@@ -163,7 +165,7 @@ void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &colle
void QmlTypesCreator::writeType(QAnyStringView type)
{
- ResolvedTypeAlias resolved(type);
+ ResolvedTypeAlias resolved(type, m_usingDeclarations);
if (resolved.type.isEmpty())
return;
@@ -173,7 +175,7 @@ void QmlTypesCreator::writeType(QAnyStringView type)
if (resolved.isPointer)
m_qml.writeBooleanBinding(S_IS_POINTER, true);
if (resolved.isConstant)
- m_qml.writeBooleanBinding(S_IS_CONSTANT, true);
+ m_qml.writeBooleanBinding(S_IS_TYPE_CONSTANT, true);
}
void QmlTypesCreator::writeProperties(const Property::Container &properties)
@@ -219,7 +221,7 @@ void QmlTypesCreator::writeProperties(const Property::Container &properties)
m_qml.writeBooleanBinding(S_IS_FINAL, true);
if (obj.isConstant)
- m_qml.writeBooleanBinding(S_IS_CONSTANT, true);
+ m_qml.writeBooleanBinding(S_IS_PROPERTY_CONSTANT, true);
if (obj.isRequired)
m_qml.writeBooleanBinding(S_IS_REQUIRED, true);
diff --git a/src/qmltyperegistrar/qqmltypescreator_p.h b/src/qmltyperegistrar/qqmltypescreator_p.h
index 10c5a3d35d..c30c00c889 100644
--- a/src/qmltyperegistrar/qqmltypescreator_p.h
+++ b/src/qmltyperegistrar/qqmltypescreator_p.h
@@ -35,6 +35,7 @@ public:
void setReferencedTypes(QList<QAnyStringView> referencedTypes) { m_referencedTypes = std::move(referencedTypes); }
void setModule(QByteArray module) { m_module = std::move(module); }
void setVersion(QTypeRevision version) { m_version = version; }
+ void setUsingDeclarations(QList<UsingDeclaration> usingDeclarations) { m_usingDeclarations = std::move(usingDeclarations);}
private:
void writeComponent(const QmlTypesClassDescription &collector);
@@ -54,6 +55,7 @@ private:
QVector<MetaType> m_ownTypes;
QVector<MetaType> m_foreignTypes;
QList<QAnyStringView> m_referencedTypes;
+ QList<UsingDeclaration> m_usingDeclarations;
QByteArray m_module;
QTypeRevision m_version = QTypeRevision::zero();
};
diff --git a/src/qmlworkerscript/CMakeLists.txt b/src/qmlworkerscript/CMakeLists.txt
index 1704d5ae16..cb1643c6f5 100644
--- a/src/qmlworkerscript/CMakeLists.txt
+++ b/src/qmlworkerscript/CMakeLists.txt
@@ -12,7 +12,7 @@ qt_internal_add_qml_module(QmlWorkerScript
PLUGIN_TARGET workerscriptplugin
CLASS_NAME QtQmlWorkerScriptPlugin
DEPENDENCIES
- QtQml.Base/auto
+ QML/1.0
SOURCES
qquickworkerscript.cpp qquickworkerscript_p.h
qtqmlworkerscriptglobal.h qtqmlworkerscriptglobal_p.h
@@ -53,7 +53,6 @@ qt_internal_add_qml_module(QmlWorkerScript
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
Qt::QmlPrivate
- GENERATE_CPP_EXPORTS
)
qt_internal_extend_target(QmlWorkerScript CONDITION disassembler AND ((TEST_architecture_arch STREQUAL "i386") OR (TEST_architecture_arch STREQUAL "x86_64"))
diff --git a/src/qmlxmllistmodel/CMakeLists.txt b/src/qmlxmllistmodel/CMakeLists.txt
index 3237ba891a..5b56f6388b 100644
--- a/src/qmlxmllistmodel/CMakeLists.txt
+++ b/src/qmlxmllistmodel/CMakeLists.txt
@@ -21,7 +21,6 @@ qt_internal_add_qml_module(QmlXmlListModel
Qt::Qml
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
- GENERATE_CPP_EXPORTS
)
qt_internal_add_docs(QmlXmlListModel
diff --git a/src/quick/CMakeLists.txt b/src/quick/CMakeLists.txt
index 86edb893c2..6f294d30d1 100644
--- a/src/quick/CMakeLists.txt
+++ b/src/quick/CMakeLists.txt
@@ -181,7 +181,7 @@ qt_internal_add_qml_module(Quick
scenegraph/util/qsgvertexcolormaterial.cpp scenegraph/util/qsgvertexcolormaterial.h
scenegraph/util/qquadpath.cpp scenegraph/util/qquadpath_p.h
scenegraph/util/qsggradientcache.cpp scenegraph/util/qsggradientcache_p.h
- util/qminimalflatset_p.h
+ scenegraph/util/qsgtransform.cpp scenegraph/util/qsgtransform_p.h
util/qquickanimation.cpp util/qquickanimation_p.h
util/qquickanimation_p_p.h
util/qquickanimationcontroller.cpp util/qquickanimationcontroller_p.h
@@ -237,17 +237,19 @@ qt_internal_add_qml_module(Quick
Qt::GuiPrivate
Qt::QmlModelsPrivate
Qt::QmlPrivate
+ Qt::QmlMetaPrivate
PUBLIC_LIBRARIES
Qt::Core
Qt::Gui
Qt::Qml
+ Qt::QmlMeta
Qt::QmlModels
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
Qt::GuiPrivate
Qt::QmlModelsPrivate
Qt::QmlPrivate
- GENERATE_CPP_EXPORTS
+ Qt::QmlMetaPrivate
)
# We need to do additional initialization, so we have to provide our own
@@ -464,6 +466,43 @@ qt_internal_add_shaders(Quick "scenegraph_curve_shaders_cg_derivatives"
"scenegraph/shaders_ng/shapecurve_cg_derivatives.vert.qsb"
)
+qt_internal_add_shaders(Quick "scenegraph_curve_shaders_tf"
+ SILENT
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ MULTIVIEW
+ DEFINES
+ "TEXTUREFILL"
+ PREFIX
+ "/qt-project.org"
+ FILES
+ "scenegraph/shaders_ng/shapecurve.frag"
+ "scenegraph/shaders_ng/shapecurve.vert"
+ OUTPUTS
+ "scenegraph/shaders_ng/shapecurve_tf.frag.qsb"
+ "scenegraph/shaders_ng/shapecurve_tf.vert.qsb"
+)
+
+qt_internal_add_shaders(Quick "scenegraph_curve_shaders_tf_derivatives"
+ SILENT
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ MULTIVIEW
+ DEFINES
+ "TEXTUREFILL"
+ "USE_DERIVATIVES"
+ PREFIX
+ "/qt-project.org"
+ FILES
+ "scenegraph/shaders_ng/shapecurve.frag"
+ "scenegraph/shaders_ng/shapecurve.vert"
+ OUTPUTS
+ "scenegraph/shaders_ng/shapecurve_tf_derivatives.frag.qsb"
+ "scenegraph/shaders_ng/shapecurve_tf_derivatives.vert.qsb"
+)
+
qt_internal_extend_target(Quick CONDITION QT_FEATURE_qml_network
LIBRARIES
Qt::Network
@@ -562,6 +601,11 @@ qt_internal_extend_target(Quick CONDITION QT_FEATURE_metal
qt_internal_extend_target(Quick CONDITION ANDROID
SOURCES
platform/android/qandroidquickviewembedding.cpp platform/android/qandroidquickviewembedding_p.h
+ platform/android/qandroidviewsignalmanager.cpp platform/android/qandroidviewsignalmanager_p.h
+ platform/android/qandroiditemmodelproxy.cpp platform/android/qandroiditemmodelproxy_p.h
+ platform/android/qandroidmodelindexproxy.cpp platform/android/qandroidmodelindexproxy_p.h
+ platform/android/qandroidtypes_p.h
+ platform/android/qandroidtypeconverter_p.h
)
if (ANDROID)
add_subdirectory(jar)
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index 514b1a9214..5824b63a4c 100644
--- a/src/quick/accessible/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -604,6 +604,20 @@ QString QAccessibleQuickItem::text(QAccessible::Text textType) const
if (!accessibleDecription.isNull())
return accessibleDecription.toString();
break;}
+ case QAccessible::Identifier: {
+ QVariant accessibleIdentifier = QQuickAccessibleAttached::property(object(), "id");
+ if (!accessibleIdentifier.isNull())
+ return accessibleIdentifier.toString();
+ auto quickItem = item();
+ if (quickItem->isComponentComplete()) {
+ QQmlContext *context = qmlContext(quickItem);
+ if (context) {
+ const auto objectId = context->nameForObject(quickItem);
+ if (!objectId.isEmpty())
+ return objectId;
+ }
+ }
+ break;}
#ifdef Q_ACCESSIBLE_QUICK_ITEM_ENABLE_DEBUG_DESCRIPTION
case QAccessible::DebugDescription: {
QString debugString;
@@ -709,19 +723,20 @@ QRect itemScreenRect(QQuickItem *item)
return QRect();
}
- QSize itemSize((int)item->width(), (int)item->height());
+ QSizeF itemSize(item->width(), item->height());
// ### If the bounding rect fails, we first try the implicit size, then we go for the
// parent size. WE MIGHT HAVE TO REVISIT THESE FALLBACKS.
if (itemSize.isEmpty()) {
- itemSize = QSize((int)item->implicitWidth(), (int)item->implicitHeight());
+ itemSize = QSize(item->implicitWidth(), item->implicitHeight());
if (itemSize.isEmpty() && item->parentItem())
// ### Seems that the above fallback is not enough, fallback to use the parent size...
- itemSize = QSize((int)item->parentItem()->width(), (int)item->parentItem()->height());
+ itemSize = QSize(item->parentItem()->width(), item->parentItem()->height());
}
- QPointF scenePoint = item->mapToScene(QPointF(0, 0));
- QPoint screenPos = item->window()->mapToGlobal(scenePoint.toPoint());
- return QRect(screenPos, itemSize);
+ QRectF sceneRect = item->mapRectToScene(QRectF(QPointF(0, 0), itemSize));
+ QPoint screenPos = item->window()->mapToGlobal(sceneRect.topLeft().toPoint());
+ QSize screenSize = sceneRect.size().toSize();
+ return QRect(screenPos, screenSize);
}
QTextDocument *QAccessibleQuickItem::textDocument() const
diff --git a/src/quick/doc/snippets/pointerHandlers/dragHandlerAcceptedButtons.qml b/src/quick/doc/snippets/pointerHandlers/dragHandlerAcceptedButtons.qml
new file mode 100644
index 0000000000..9aeceb04f6
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/dragHandlerAcceptedButtons.qml
@@ -0,0 +1,81 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+pragma ComponentBehavior: Bound
+import QtQuick
+import Qt.labs.animation
+import Qt.labs.folderlistmodel
+
+//![0]
+Rectangle {
+ id: canvas
+ width: 640
+ height: 480
+ color: "#333"
+ property int highestZ: 0
+
+ Repeater {
+ model: FolderListModel { nameFilters: ["*.qml"] }
+
+ delegate: Rectangle {
+ required property string fileName
+ required property url fileUrl
+ required property int index
+
+ id: frame
+ x: index * 30; y: index * 30
+ width: 320; height: 240
+ property bool dragging: ldh.active || rdh.active
+ onDraggingChanged: if (dragging) z = ++canvas.highestZ
+ border { width: 2; color: dragging ? "red" : "steelblue" }
+ color: "beige"
+ clip: true
+
+ TextEdit {
+ // drag to select text
+ id: textEdit
+ textDocument.source: frame.fileUrl
+ x: 3; y: 3
+
+ BoundaryRule on y {
+ id: ybr
+ minimum: textEdit.parent.height - textEdit.height; maximum: 0
+ minimumOvershoot: 200; maximumOvershoot: 200
+ overshootFilter: BoundaryRule.Peak
+ }
+ }
+
+ DragHandler {
+ id: rdh
+ // right-drag to position the "window"
+ acceptedButtons: Qt.RightButton
+ }
+
+ WheelHandler {
+ target: textEdit
+ property: "y"
+ onActiveChanged: if (!active) ybr.returnToBounds()
+ }
+
+ Rectangle {
+ anchors.right: parent.right
+ width: titleText.implicitWidth + 12
+ height: titleText.implicitHeight + 6
+ border { width: 2; color: parent.border.color }
+ bottomLeftRadius: 6
+ Text {
+ id: titleText
+ color: "saddlebrown"
+ anchors.centerIn: parent
+ text: frame.fileName
+ textFormat: Text.PlainText
+ }
+ DragHandler {
+ id: ldh
+ // left-drag to position the "window"
+ target: frame
+ }
+ }
+ }
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/dragHandlerMargin.qml b/src/quick/doc/snippets/pointerHandlers/dragHandlerMargin.qml
new file mode 100644
index 0000000000..7844d118e4
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/dragHandlerMargin.qml
@@ -0,0 +1,27 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+import QtQuick
+
+//! [entire]
+Item {
+ width: 320
+ height: 240
+ //![draggable]
+ Rectangle {
+ width: 24
+ height: 24
+ border.color: "steelblue"
+ Text {
+ text: "it's\ntiny"
+ font.pixelSize: 7
+ rotation: -45
+ anchors.centerIn: parent
+ }
+
+ DragHandler {
+ margin: 12
+ }
+ }
+ //![draggable]
+}
+//! [entire]
diff --git a/src/quick/doc/snippets/pointerHandlers/draggableGridView.qml b/src/quick/doc/snippets/pointerHandlers/draggableGridView.qml
new file mode 100644
index 0000000000..f3a0cac8d2
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/draggableGridView.qml
@@ -0,0 +1,121 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+pragma ComponentBehavior: Bound
+import QtQml
+import QtQuick
+import QtQml.Models
+
+//! [entire]
+GridView {
+ id: root
+ width: 320
+ height: 480
+ cellWidth: 80
+ cellHeight: 80
+ interactive: false
+
+ displaced: Transition {
+ NumberAnimation {
+ properties: "x,y"
+ easing.type: Easing.OutQuad
+ }
+ }
+
+ model: DelegateModel {
+ id: visualModel
+ model: 24
+ property var dropTarget: undefined
+ property bool copy: false
+ delegate: DropArea {
+ id: delegateRoot
+
+ width: 80
+ height: 80
+
+ onEntered: drag => {
+ if (visualModel.copy) {
+ if (drag.source !== icon)
+ visualModel.dropTarget = icon
+ } else {
+ visualModel.items.move(drag.source.DelegateModel.itemsIndex, icon.DelegateModel.itemsIndex)
+ }
+ }
+
+ Rectangle {
+ id: icon
+ objectName: DelegateModel.itemsIndex
+
+ property string text
+ Component.onCompleted: {
+ color = Qt.rgba(0.2 + (48 - DelegateModel.itemsIndex) * Math.random() / 48,
+ 0.3 + DelegateModel.itemsIndex * Math.random() / 48,
+ 0.4 * Math.random(),
+ 1.0)
+ text = DelegateModel.itemsIndex
+ }
+ border.color: visualModel.dropTarget === this ? "black" : "transparent"
+ border.width: 2
+ radius: 3
+ width: 72
+ height: 72
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ verticalCenter: parent.verticalCenter
+ }
+
+ states: [
+ State {
+ when: dragHandler.active || controlDragHandler.active
+ ParentChange {
+ target: icon
+ parent: root
+ }
+
+ AnchorChanges {
+ target: icon
+ anchors {
+ horizontalCenter: undefined
+ verticalCenter: undefined
+ }
+ }
+ }
+ ]
+
+ Text {
+ anchors.centerIn: parent
+ color: "white"
+ font.pointSize: 14
+ text: controlDragHandler.active ? "+" : icon.text
+ }
+
+ //! [draghandlers]
+ DragHandler {
+ id: dragHandler
+ acceptedModifiers: Qt.NoModifier
+ onActiveChanged: if (!active) visualModel.dropTarget = undefined
+ }
+
+ DragHandler {
+ id: controlDragHandler
+ acceptedModifiers: Qt.ControlModifier
+ onActiveChanged: {
+ visualModel.copy = active
+ if (!active) {
+ visualModel.dropTarget.text = icon.text
+ visualModel.dropTarget.color = icon.color
+ visualModel.dropTarget = undefined
+ }
+ }
+ }
+ //! [draghandlers]
+
+ Drag.active: dragHandler.active || controlDragHandler.active
+ Drag.source: icon
+ Drag.hotSpot.x: 36
+ Drag.hotSpot.y: 36
+ }
+ }
+ }
+}
+//! [entire]
diff --git a/src/quick/doc/snippets/pointerHandlers/pinchHandler.qml b/src/quick/doc/snippets/pointerHandlers/pinchHandlerSimple.qml
index e25d23da2a..b78a1d7871 100644
--- a/src/quick/doc/snippets/pointerHandlers/pinchHandler.qml
+++ b/src/quick/doc/snippets/pointerHandlers/pinchHandlerSimple.qml
@@ -1,6 +1,7 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-//![0]
+
+//! [0]
import QtQuick
Rectangle {
@@ -9,4 +10,4 @@ Rectangle {
color: "lightsteelblue"
PinchHandler { }
}
-//![0]
+//! [0]
diff --git a/src/quick/doc/snippets/qml/font.qml b/src/quick/doc/snippets/qml/font.qml
new file mode 100644
index 0000000000..5f76d6fc30
--- /dev/null
+++ b/src/quick/doc/snippets/qml/font.qml
@@ -0,0 +1,22 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+
+Item {
+//! [text]
+ Text {
+ font.family: "Helvetica"
+ font.pointSize: 13
+ font.bold: true
+ }
+//! [text]
+
+//! [structured-value-construction]
+ readonly property font myFont: ({
+ family: "Helvetica",
+ pointSize: 13,
+ bold: true
+ })
+//! [structured-value-construction]
+}
diff --git a/src/quick/doc/snippets/qml/tableview/editdelegate.qml b/src/quick/doc/snippets/qml/tableview/editdelegate.qml
index 11de5f5434..c5274e5ac7 100644
--- a/src/quick/doc/snippets/qml/tableview/editdelegate.qml
+++ b/src/quick/doc/snippets/qml/tableview/editdelegate.qml
@@ -46,7 +46,7 @@ Window {
display = text
// 'display = text' is short-hand for:
// let index = TableView.view.index(row, column)
- // TableView.view.model.setData(index, text, Qt.DisplayRole)
+ // TableView.view.model.setData(index, "display", text)
}
}
}
diff --git a/src/quick/doc/snippets/qml/windowPalette.qml b/src/quick/doc/snippets/qml/windowPalette.qml
index 0638213c57..5a9219c638 100644
--- a/src/quick/doc/snippets/qml/windowPalette.qml
+++ b/src/quick/doc/snippets/qml/windowPalette.qml
@@ -17,12 +17,14 @@ Window {
palette.active.window: "peachpuff"
palette.windowText: "brown"
+//![text-item]
Text {
anchors.centerIn: parent
// here we use the Window.active attached property and the Item.palette property
color: Window.active ? palette.active.windowText : palette.inactive.windowText
text: Window.active ? "active" : "inactive"
}
+//![text-item]
Button {
text: "Button"
diff --git a/src/quick/doc/snippets/qquickrhiitem/qquickrhiitem_intro.frag b/src/quick/doc/snippets/qquickrhiitem/qquickrhiitem_intro.frag
new file mode 100644
index 0000000000..d86bcf7386
--- /dev/null
+++ b/src/quick/doc/snippets/qquickrhiitem/qquickrhiitem_intro.frag
@@ -0,0 +1,10 @@
+//![0]
+#version 440
+layout(location = 0) in vec3 v_color;
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(v_color, 1.0);
+}
+//![0]
diff --git a/src/quick/doc/snippets/qquickrhiitem/qquickrhiitem_intro.vert b/src/quick/doc/snippets/qquickrhiitem/qquickrhiitem_intro.vert
new file mode 100644
index 0000000000..610df304b1
--- /dev/null
+++ b/src/quick/doc/snippets/qquickrhiitem/qquickrhiitem_intro.vert
@@ -0,0 +1,15 @@
+//![0]
+#version 440
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec3 color;
+layout(location = 0) out vec3 v_color;
+layout(std140, binding = 0) uniform buf {
+ mat4 mvp;
+};
+
+void main()
+{
+ v_color = color;
+ gl_Position = mvp * position;
+}
+//![0]
diff --git a/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc b/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc
index 17f6c31238..f87397f413 100644
--- a/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc
+++ b/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc
@@ -58,6 +58,15 @@ capable of rendering changes to the code in realtime. It avoids the need to
rebuild the application after every code change and install it on the target
device. You can also extend it to build a custom runtime that suits your needs.
+\section1 Felgo QML Hot Reload
+
+\l{Felgo QML Hot Reload Tool}{Felgo QML Hot Reload} is a third-party tool that
+updates QML and JavaScript code in your running application without recompiling
+and redeploying after each change. Unlike Live Reload, it preserves the
+application's current state after a reload and can run on multiple devices
+simultaneously to test and iterate code. Felgo Hot Reload supports all Qt
+target platforms and architectures.
+
\section1 GammaRay
\l{GammaRay Manual}{GammaRay} is a useful utility that provides diagnostic
diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc
index e1ebca8106..db750bf077 100644
--- a/src/quick/doc/src/qmltypereference.qdoc
+++ b/src/quick/doc/src/qmltypereference.qdoc
@@ -54,7 +54,7 @@ In addition, the \c QtQuick import provides the following value types:
\section1 Object Types
Most object types provided by the \c QtQuick import are based on the \l{Item}
-type, which itself derives from \l{QtQml::QtObject}{QtObject}. \l{Qt QML QML
+type, which itself derives from \l{QtQml::QtObject}{QtObject}. \l{Qt Qml QML
Types#Object Types} {QML object types} provided by the Qt QML module (such as
\l{QtQml::QtObject}{QtObject} and \l{QtQml::Component}{Component}) are also
available when you import \c QtQuick.
@@ -114,7 +114,7 @@ available when you import \c QtQuick.
\section1 SVG Color Reference
The following table lists the available
- \l {http://www.w3.org/TR/SVG/types.html#ColorKeywords}{SVG colors}:
+ \l {https://www.w3.org/TR/css-color-3/#svg-color}{SVG colors}:
\include svg-colors.qdocinc
@@ -160,12 +160,18 @@ available when you import \c QtQuick.
\li \c object \l [QML] {QtQuick::Text::}{font.features}
\li \l string \c font.styleName
\li \c object \c [QML] {QtQuick::Text::}{font.variableAxes}
+ \li \l bool \c font.contextFontMerging
+ \li \l bool \c font.preferTypoLineMetrics
\endlist
Example:
- \qml
- Text { font.family: "Helvetica"; font.pointSize: 13; font.bold: true }
- \endqml
+
+ \snippet qml/font.qml text
+
+ As \c font is a \l {QML_STRUCTURED_VALUE}{structured value} type, it can
+ also be constructed with a JavaScript object:
+
+ \snippet qml/font.qml structured-value-construction
When integrating with C++, note that any QFont value
\l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
diff --git a/src/quick/doc/src/qtquick.qdoc b/src/quick/doc/src/qtquick.qdoc
index 31dd680d93..0d0890398f 100644
--- a/src/quick/doc/src/qtquick.qdoc
+++ b/src/quick/doc/src/qtquick.qdoc
@@ -143,6 +143,13 @@ To find out more about using the QML language, see the \l{Qt Qml} module documen
- provides classes for using QML with Java/Kotlin Android APIs.
\endlist
+\section1 Qt Academy Courses
+ \list
+ \li \l {https://www.qt.io/academy/course-catalog#introduction-to-qt-quick}
+ {Introduction to Qt Quick}
+ \endlist
+
+
\section1 Licenses and Attributions
Qt Quick is available under commercial licenses from \l{The Qt Company}.
diff --git a/src/quick/handlers/qquickdragaxis.cpp b/src/quick/handlers/qquickdragaxis.cpp
index 84b1b7ee07..7d8203eb06 100644
--- a/src/quick/handlers/qquickdragaxis.cpp
+++ b/src/quick/handlers/qquickdragaxis.cpp
@@ -7,7 +7,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcDragAxis, "qt.quick.pointer.dragaxis")
+Q_STATIC_LOGGING_CATEGORY(lcDragAxis, "qt.quick.pointer.dragaxis")
QQuickDragAxis::QQuickDragAxis(QQuickPointerHandler *handler, const QString &propertyName, qreal initValue)
: QObject(handler), m_accumulatedValue(initValue), m_propertyName(propertyName)
diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp
index 5e9d6d8230..3d5f26b43a 100644
--- a/src/quick/handlers/qquickdraghandler.cpp
+++ b/src/quick/handlers/qquickdraghandler.cpp
@@ -10,7 +10,7 @@ QT_BEGIN_NAMESPACE
static const qreal DragAngleToleranceDegrees = 10;
-Q_LOGGING_CATEGORY(lcDragHandler, "qt.quick.handler.drag")
+Q_STATIC_LOGGING_CATEGORY(lcDragHandler, "qt.quick.handler.drag")
/*!
\qmltype DragHandler
@@ -368,6 +368,93 @@ void QQuickDragHandler::setActiveTranslation(const QVector2D &trans)
\c {0, 0} again.
*/
+/*!
+ \qmlproperty flags QtQuick::DragHandler::acceptedButtons
+
+ The mouse buttons that can activate this DragHandler.
+
+ By default, this property is set to
+ \l {QtQuick::MouseEvent::button} {Qt.LeftButton}.
+ It can be set to an OR combination of mouse buttons, and will ignore events
+ from other buttons.
+
+ For example, if a component (such as TextEdit) already handles
+ left-button drags in its own way, it can be augmented with a
+ DragHandler that does something different when dragged via the
+ right button:
+
+ \snippet pointerHandlers/dragHandlerAcceptedButtons.qml 0
+*/
+
+/*!
+ \qmlproperty flags DragHandler::acceptedDevices
+
+ The types of pointing devices that can activate this DragHandler.
+
+ By default, this property is set to
+ \l{QInputDevice::DeviceType}{PointerDevice.AllDevices}.
+ If you set it to an OR combination of device types, it will ignore events
+ from non-matching devices.
+
+ \note Not all platforms are yet able to distinguish mouse and touchpad; and
+ on those that do, you often want to make mouse and touchpad behavior the same.
+*/
+
+/*!
+ \qmlproperty flags DragHandler::acceptedModifiers
+
+ If this property is set, it will require the given keyboard modifiers to
+ be pressed in order to react to pointer events, and otherwise ignore them.
+
+ For example, two DragHandlers can perform two different drag-and-drop
+ operations, depending on whether the \c Control modifier is pressed:
+
+ \snippet pointerHandlers/draggableGridView.qml entire
+
+ If this property is set to \c Qt.KeyboardModifierMask (the default value),
+ then the DragHandler ignores the modifier keys.
+
+ If you set \c acceptedModifiers to an OR combination of modifier keys,
+ it means \e all of those modifiers must be pressed to activate the handler.
+
+ The available modifiers are as follows:
+
+ \value NoModifier No modifier key is allowed.
+ \value ShiftModifier A Shift key on the keyboard must be pressed.
+ \value ControlModifier A Ctrl key on the keyboard must be pressed.
+ \value AltModifier An Alt key on the keyboard must be pressed.
+ \value MetaModifier A Meta key on the keyboard must be pressed.
+ \value KeypadModifier A keypad button must be pressed.
+ \value GroupSwitchModifier X11 only (unless activated on Windows by a command line argument).
+ A Mode_switch key on the keyboard must be pressed.
+ \value KeyboardModifierMask The handler does not care which modifiers are pressed.
+
+ \sa Qt::KeyboardModifier
+*/
+
+/*!
+ \qmlproperty flags DragHandler::acceptedPointerTypes
+
+ The types of pointing instruments (finger, stylus, eraser, etc.)
+ that can activate this DragHandler.
+
+ By default, this property is set to
+ \l {QPointingDevice::PointerType} {PointerDevice.AllPointerTypes}.
+ If you set it to an OR combination of device types, it will ignore events
+ from non-matching \l {PointerDevice}{devices}.
+*/
+
+/*!
+ \qmlproperty real DragHandler::margin
+
+ The margin beyond the bounds of the \l {PointerHandler::parent}{parent}
+ item within which an \l eventPoint can activate this handler. For example,
+ you can make it easier to drag small items by allowing the user to drag
+ from a position nearby:
+
+ \snippet pointerHandlers/dragHandlerMargin.qml draggable
+*/
+
QT_END_NAMESPACE
#include "moc_qquickdraghandler_p.cpp"
diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp
index cbbb14fd8c..c9a197d3dc 100644
--- a/src/quick/handlers/qquickhandlerpoint.cpp
+++ b/src/quick/handlers/qquickhandlerpoint.cpp
@@ -6,7 +6,6 @@
#include "private/qquickdeliveryagent_p_p.h"
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcTouchTarget)
/*!
\qmltype handlerPoint
diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp
index 5bf53235c5..863275c087 100644
--- a/src/quick/handlers/qquickhoverhandler.cpp
+++ b/src/quick/handlers/qquickhoverhandler.cpp
@@ -8,7 +8,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcHoverHandler, "qt.quick.handler.hover")
+Q_STATIC_LOGGING_CATEGORY(lcHoverHandler, "qt.quick.handler.hover")
/*!
\qmltype HoverHandler
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index 8de7390ae4..92a1777137 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -17,7 +17,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcPinchHandler, "qt.quick.handler.pinch")
+Q_STATIC_LOGGING_CATEGORY(lcPinchHandler, "qt.quick.handler.pinch")
/*!
\qmltype PinchHandler
@@ -32,7 +32,7 @@ Q_LOGGING_CATEGORY(lcPinchHandler, "qt.quick.handler.pinch")
by default it is fully functional, and manipulates its \l target,
which is the Item within which it is declared.
- \snippet pointerHandlers/pinchHandler.qml 0
+ \snippet pointerHandlers/pinchHandlerSimple.qml 0
It has properties to restrict the range of dragging, rotation, and zoom.
diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp
index a29c8ae2d3..92e726bdcc 100644
--- a/src/quick/handlers/qquickpointerhandler.cpp
+++ b/src/quick/handlers/qquickpointerhandler.cpp
@@ -13,9 +13,8 @@
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcPointerHandlerDispatch, "qt.quick.handler.dispatch")
-Q_LOGGING_CATEGORY(lcPointerHandlerGrab, "qt.quick.handler.grab")
-Q_LOGGING_CATEGORY(lcPointerHandlerActive, "qt.quick.handler.active")
-Q_DECLARE_LOGGING_CATEGORY(lcHandlerParent)
+Q_STATIC_LOGGING_CATEGORY(lcPointerHandlerGrab, "qt.quick.handler.grab")
+Q_STATIC_LOGGING_CATEGORY(lcPointerHandlerActive, "qt.quick.handler.active")
/*!
\qmltype PointerHandler
diff --git a/src/quick/handlers/qquickpointerhandler_p.h b/src/quick/handlers/qquickpointerhandler_p.h
index e54338f677..32a316bd44 100644
--- a/src/quick/handlers/qquickpointerhandler_p.h
+++ b/src/quick/handlers/qquickpointerhandler_p.h
@@ -145,6 +145,7 @@ protected:
friend class QQuickDeliveryAgentPrivate;
friend class QQuickItemPrivate;
+ friend class QQuickMenuPrivate;
friend class QQuickWindowPrivate;
Q_DECLARE_PRIVATE(QQuickPointerHandler)
diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp
index d2c38179a3..52e3f8ce5f 100644
--- a/src/quick/handlers/qquicksinglepointhandler.cpp
+++ b/src/quick/handlers/qquicksinglepointhandler.cpp
@@ -4,8 +4,9 @@
#include "qquicksinglepointhandler_p.h"
#include "qquicksinglepointhandler_p_p.h"
+#include <private/qquickdeliveryagent_p.h>
+
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcTouchTarget)
/*!
\qmltype SinglePointHandler
diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp
index accf307382..76f89feb3a 100644
--- a/src/quick/handlers/qquicktaphandler.cpp
+++ b/src/quick/handlers/qquicktaphandler.cpp
@@ -11,7 +11,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcTapHandler, "qt.quick.handler.tap")
+Q_STATIC_LOGGING_CATEGORY(lcTapHandler, "qt.quick.handler.tap")
quint64 QQuickTapHandler::m_multiTapInterval(0);
// single tap distance is the same as the drag threshold
@@ -441,7 +441,8 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QPointerEvent *event,
}
if (cancel) {
emit canceled(point);
- setExclusiveGrab(event, point, false);
+ if (event)
+ setExclusiveGrab(event, point, false);
// In case there is a filtering parent (Flickable), we should not give up the passive grab,
// so that it can continue to filter future events.
d_func()->reset();
diff --git a/src/quick/handlers/qquickwheelhandler.cpp b/src/quick/handlers/qquickwheelhandler.cpp
index 34110ff6cc..7e29af1422 100644
--- a/src/quick/handlers/qquickwheelhandler.cpp
+++ b/src/quick/handlers/qquickwheelhandler.cpp
@@ -9,7 +9,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcWheelHandler, "qt.quick.handler.wheel")
+Q_STATIC_LOGGING_CATEGORY(lcWheelHandler, "qt.quick.handler.wheel")
/*!
\qmltype WheelHandler
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index 2dadae3ef7..7a468ee0c5 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -12,7 +12,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcCanvas, "qt.quick.canvas")
+Q_STATIC_LOGGING_CATEGORY(lcCanvas, "qt.quick.canvas")
QQuickContext2DTexture::QQuickContext2DTexture()
: m_context(nullptr)
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 865fb8bf11..4a5dfa4111 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -120,6 +120,15 @@ QT_BEGIN_NAMESPACE
\endtable
*/
+/*!
+ \qmlproperty string QtQuick::Accessible::id
+
+ This property sets an identifier for the object.
+ It can be used to provide stable identifiers to UI tests.
+ By default, the identifier is set to the ID of the QML object.
+ If the ID is not set the default of \l QAccessible::Identifier is used.
+*/
+
/*! \qmlproperty bool QtQuick::Accessible::focusable
\brief This property holds whether this item is focusable.
@@ -301,15 +310,19 @@ QQuickAccessibleAttached::QQuickAccessibleAttached(QObject *parent)
: QObject(parent), m_role(QAccessible::NoRole)
{
Q_ASSERT(parent);
- if (!item()) {
- qmlWarning(parent) << "Accessible must be attached to an Item";
- return;
- }
-
// Enable accessibility for items with accessible content. This also
- // enables accessibility for the ancestors of souch items.
- item()->d_func()->setAccessible();
- QAccessibleEvent ev(item(), QAccessible::ObjectCreated);
+ // enables accessibility for the ancestors of such items.
+ auto item = qobject_cast<QQuickItem *>(parent);
+ if (item) {
+ item->d_func()->setAccessible();
+ } else {
+ const QLatin1StringView className(QQmlData::ensurePropertyCache(parent)->firstCppMetaObject()->className());
+ if (className != QLatin1StringView("QQuickAction")) {
+ qmlWarning(parent) << "Accessible must be attached to an Item or an Action";
+ return;
+ }
+ }
+ QAccessibleEvent ev(parent, QAccessible::ObjectCreated);
QAccessible::updateAccessibility(&ev);
if (const QMetaObject *pmo = parent->metaObject()) {
@@ -423,13 +436,15 @@ QQuickAccessibleAttached *QQuickAccessibleAttached::qmlAttachedProperties(QObjec
bool QQuickAccessibleAttached::ignored() const
{
- return item() ? !item()->d_func()->isAccessible : false;
+ auto item = qobject_cast<QQuickItem *>(parent());
+ return item ? !item->d_func()->isAccessible : false;
}
void QQuickAccessibleAttached::setIgnored(bool ignored)
{
- if (this->ignored() != ignored && item()) {
- item()->d_func()->isAccessible = !ignored;
+ auto item = qobject_cast<QQuickItem *>(parent());
+ if (item && this->ignored() != ignored) {
+ item->d_func()->isAccessible = !ignored;
emit ignoredChanged();
}
}
@@ -457,8 +472,13 @@ bool QQuickAccessibleAttached::doAction(const QString &actionName)
sig = &sigPreviousPage;
else if (actionName == QAccessibleActionInterface::nextPageAction())
sig = &sigNextPage;
- if (sig && isSignalConnected(*sig))
- return sig->invoke(this);
+ if (sig && isSignalConnected(*sig)) {
+ bool ret = false;
+ if (m_proxying)
+ ret = sig->invoke(m_proxying);
+ ret |= sig->invoke(this);
+ return ret;
+ }
return false;
}
@@ -497,6 +517,69 @@ QString QQuickAccessibleAttached::stripHtml(const QString &html)
#endif
}
+void QQuickAccessibleAttached::setProxying(QQuickAccessibleAttached *proxying)
+{
+ if (proxying == m_proxying)
+ return;
+
+ const QMetaObject &mo = staticMetaObject;
+ if (m_proxying) {
+ // We disconnect all signals from the proxy into this object
+ auto mo = m_proxying->metaObject();
+ auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
+ for (int signalIndex = propertyCache->signalOffset();
+ signalIndex < propertyCache->signalCount(); ++signalIndex) {
+ const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
+ Q_ASSERT(m.methodType() == QMetaMethod::Signal);
+ if (m.methodType() != QMetaMethod::Signal)
+ continue;
+
+ disconnect(m_proxying, m, this, m);
+ }
+ }
+
+ m_proxying = proxying;
+
+ if (m_proxying) {
+ // We connect all signals from the proxy into this object
+ auto propertyCache = QQmlData::ensurePropertyCache(m_proxying);
+ auto mo = m_proxying->metaObject();
+ for (int signalIndex = propertyCache->signalOffset();
+ signalIndex < propertyCache->signalCount(); ++signalIndex) {
+ const QMetaMethod m = mo->method(propertyCache->signal(signalIndex)->coreIndex());
+ Q_ASSERT(m.methodType() == QMetaMethod::Signal);
+ connect(proxying, m, this, m);
+ }
+ }
+
+ // We check all properties
+ for (int prop = mo.propertyOffset(); prop < mo.propertyCount(); ++prop) {
+ const QMetaProperty p = mo.property(prop);
+ if (!p.hasNotifySignal()) {
+ continue;
+ }
+
+ const QMetaMethod signal = p.notifySignal();
+ if (signal.parameterCount() == 0)
+ signal.invoke(this);
+ else
+ signal.invoke(this, Q_ARG(bool, p.read(this).toBool()));
+ }
+}
+
+/*!
+ * \since 6.8
+ * Issues an announcement event with a \a message with politeness \a politeness.
+ *
+ * \sa QAccessibleAnnouncementEvent
+ */
+void QQuickAccessibleAttached::announce(const QString &message, QAccessible::AnnouncementPoliteness politeness)
+{
+ QAccessibleAnnouncementEvent event(parent(), message);
+ event.setPoliteness(politeness);
+ QAccessible::updateAccessibility(&event);
+}
+
QT_END_NAMESPACE
#include "moc_qquickaccessibleattached_p.cpp"
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index 92d1307a9a..aa15b437ce 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -30,9 +30,11 @@ QT_BEGIN_NAMESPACE
#define STATE_PROPERTY(P) \
Q_PROPERTY(bool P READ P WRITE set_ ## P NOTIFY P ## Changed FINAL) \
- bool P() const { return m_state.P ; } \
+ bool P() const { return m_proxying && !m_stateExplicitlySet.P ? m_proxying->P() : m_state.P ; } \
void set_ ## P(bool arg) \
{ \
+ if (m_proxying) \
+ m_proxying->set_##P(arg);\
m_stateExplicitlySet.P = true; \
if (m_state.P == arg) \
return; \
@@ -51,6 +53,7 @@ class Q_QUICK_EXPORT QQuickAccessibleAttached : public QObject
Q_PROPERTY(QAccessible::Role role READ role WRITE setRole NOTIFY roleChanged FINAL)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL)
Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged FINAL)
+ Q_PROPERTY(QString id READ id WRITE setId NOTIFY idChanged REVISION(6, 8) FINAL)
Q_PROPERTY(bool ignored READ ignored WRITE setIgnored NOTIFY ignoredChanged FINAL)
QML_NAMED_ELEMENT(Accessible)
@@ -84,6 +87,8 @@ public:
QString name() const {
if (m_state.passwordEdit)
return QString();
+ if (m_proxying)
+ return m_proxying->name();
return m_name;
}
@@ -99,9 +104,15 @@ public:
}
void setNameImplicitly(const QString &name);
- QString description() const { return m_description; }
+ QString description() const {
+ return !m_descriptionExplicitlySet && m_proxying ? m_proxying->description() : m_description;
+ }
void setDescription(const QString &description)
{
+ if (!m_descriptionExplicitlySet && m_proxying) {
+ disconnect(m_proxying, &QQuickAccessibleAttached::descriptionChanged, this, &QQuickAccessibleAttached::descriptionChanged);
+ }
+ m_descriptionExplicitlySet = true;
if (m_description != description) {
m_description = description;
Q_EMIT descriptionChanged();
@@ -110,6 +121,17 @@ public:
}
}
+ QString id() const { return m_id; }
+ void setId(const QString &id)
+ {
+ if (m_id != id) {
+ m_id = id;
+ Q_EMIT idChanged();
+ QAccessibleEvent ev(parent(), QAccessible::IdentifierChanged);
+ QAccessible::updateAccessibility(&ev);
+ }
+ }
+
// Factory function
static QQuickAccessibleAttached *qmlAttachedProperties(QObject *obj);
@@ -143,6 +165,13 @@ public:
if (att && (role == QAccessible::NoRole || att->role() == role)) {
break;
}
+ if (auto action = object->property("action").value<QObject *>(); action) {
+ QQuickAccessibleAttached *att = QQuickAccessibleAttached::attachedProperties(action);
+ if (att && (role == QAccessible::NoRole || att->role() == role)) {
+ object = action;
+ break;
+ }
+ }
object = object->parent();
}
return object;
@@ -154,6 +183,9 @@ public:
void availableActions(QStringList *actions) const;
Q_REVISION(6, 2) Q_INVOKABLE static QString stripHtml(const QString &html);
+ void setProxying(QQuickAccessibleAttached *proxying);
+
+ Q_REVISION(6, 8) Q_INVOKABLE void announce(const QString &message, QAccessible::AnnouncementPoliteness politeness = QAccessible::AnnouncementPoliteness::Polite);
public Q_SLOTS:
void valueChanged() {
@@ -171,6 +203,7 @@ Q_SIGNALS:
void roleChanged();
void nameChanged();
void descriptionChanged();
+ void idChanged();
void ignoredChanged();
void pressAction();
void toggleAction();
@@ -184,14 +217,15 @@ Q_SIGNALS:
void nextPageAction();
private:
- QQuickItem *item() const { return qobject_cast<QQuickItem*>(parent()); }
-
QAccessible::Role m_role;
QAccessible::State m_state;
QAccessible::State m_stateExplicitlySet;
QString m_name;
bool m_nameExplicitlySet = false;
QString m_description;
+ bool m_descriptionExplicitlySet = false;
+ QQuickAccessibleAttached* m_proxying = nullptr;
+ QString m_id;
static QMetaMethod sigPress;
static QMetaMethod sigToggle;
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index 40daf518d3..004f0491bd 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -400,11 +400,16 @@ void QQuickBorderImage::requestFinished()
{
Q_D(QQuickBorderImage);
- const QSize impsize = d->pix.implicitSize();
+ if (d->pendingPix != d->currentPix) {
+ std::swap(d->pendingPix, d->currentPix);
+ d->pendingPix->clear(this); // Clear the old image
+ }
+
+ const QSize impsize = d->currentPix->implicitSize();
setImplicitSize(impsize.width() / d->devicePixelRatio, impsize.height() / d->devicePixelRatio);
- if (d->pix.isError()) {
- qmlWarning(this) << d->pix.error();
+ if (d->currentPix->isError()) {
+ qmlWarning(this) << d->currentPix->error();
d->setStatus(Error);
d->setProgress(0);
} else {
@@ -416,8 +421,8 @@ void QQuickBorderImage::requestFinished()
d->oldSourceSize = sourceSize();
emit sourceSizeChanged();
}
- if (d->frameCount != d->pix.frameCount()) {
- d->frameCount = d->pix.frameCount();
+ if (d->frameCount != d->currentPix->frameCount()) {
+ d->frameCount = d->currentPix->frameCount();
emit frameCountChanged();
}
@@ -507,7 +512,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
{
Q_D(QQuickBorderImage);
- QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window());
+ QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->currentPix->textureFactory(), window());
if (!texture || width() <= 0 || height() <= 0) {
delete oldNode;
@@ -532,7 +537,7 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
QRectF innerSourceRect;
QRectF subSourceRect;
d->calculateRects(d->border,
- QSize(d->pix.width(), d->pix.height()), QSizeF(width(), height()),
+ QSize(d->currentPix->width(), d->currentPix->height()), QSizeF(width(), height()),
d->horizontalTileMode, d->verticalTileMode, d->devicePixelRatio,
&targetRect, &innerTargetRect,
&innerSourceRect, &subSourceRect);
@@ -577,6 +582,13 @@ void QQuickBorderImage::pixmapChange()
frameCount is the number of frames in the image. Most images have only one frame.
*/
+/*!
+ \qmlproperty bool QtQuick::BorderImage::retainWhileLoading
+ \since 6.8
+
+ \include qquickimage.cpp qml-image-retainwhileloading
+ */
+
QT_END_NAMESPACE
#include "moc_qquickborderimage_p.cpp"
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 715f75cde7..02efca3d07 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -29,12 +29,11 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcHandlerParent)
-Q_LOGGING_CATEGORY(lcFlickable, "qt.quick.flickable")
-Q_LOGGING_CATEGORY(lcFilter, "qt.quick.flickable.filter")
-Q_LOGGING_CATEGORY(lcReplay, "qt.quick.flickable.replay")
-Q_LOGGING_CATEGORY(lcWheel, "qt.quick.flickable.wheel")
-Q_LOGGING_CATEGORY(lcVel, "qt.quick.flickable.velocity")
+Q_STATIC_LOGGING_CATEGORY(lcFlickable, "qt.quick.flickable")
+Q_STATIC_LOGGING_CATEGORY(lcFilter, "qt.quick.flickable.filter")
+Q_STATIC_LOGGING_CATEGORY(lcReplay, "qt.quick.flickable.replay")
+Q_STATIC_LOGGING_CATEGORY(lcWheel, "qt.quick.flickable.wheel")
+Q_STATIC_LOGGING_CATEGORY(lcVel, "qt.quick.flickable.velocity")
// RetainGrabVelocity is the maxmimum instantaneous velocity that
// will ensure the Flickable retains the grab on consecutive flicks.
@@ -1646,7 +1645,6 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
d->pressed = false;
d->scrollingPhase = false;
d->draggingEnding();
- event->accept();
returnToBounds();
d->lastPosTime = -1;
d->stealMouse = false;
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index 8d251ba9ff..e9f452f3d7 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -62,18 +62,12 @@ public:
struct AxisData {
AxisData(QQuickFlickablePrivate *fp, void (QQuickFlickablePrivate::*func)(qreal))
: move(fp, func)
- , transitionToBounds(nullptr)
- , viewSize(-1), lastPos(0), previousDragDelta(0), velocity(0), startMargin(0), endMargin(0)
- , origin(0), overshoot(0)
- , transitionTo(0)
- , continuousFlickVelocity(0), velocityTime(), vTime(0)
, smoothVelocity(fp), atEnd(false), atBeginning(true)
, transitionToSet(false)
, fixingUp(false), inOvershoot(false), inRebound(false), moving(false), flicking(false)
, flickingWhenDragBegan(false), dragging(false), extentsChanged(false)
- , explicitValue(false), minExtentDirty(true), maxExtentDirty(true)
- , contentPositionChangedExternallyDuringDrag(false)
- , unused(0)
+ , explicitValue(false), contentPositionChangedExternallyDuringDrag(false)
+ , minExtentDirty(true), maxExtentDirty(true)
{}
~AxisData();
@@ -101,26 +95,27 @@ public:
void updateVelocity();
QQuickTimeLineValueProxy<QQuickFlickablePrivate> move;
- QQuickFlickableReboundTransition *transitionToBounds;
- qreal viewSize;
- qreal pressPos;
- qreal lastPos;
- qreal dragStartOffset;
- qreal dragMinBound;
- qreal dragMaxBound;
- qreal previousDragDelta;
- qreal velocity;
- qreal flickTarget;
- qreal startMargin;
- qreal endMargin;
- qreal origin;
- qreal overshoot;
- qreal transitionTo;
- qreal continuousFlickVelocity;
+ QQuickFlickableReboundTransition *transitionToBounds = nullptr;
+ qreal viewSize = -1;
+ qreal pressPos = 0;
+ qreal lastPos = 0;
+ qreal dragStartOffset = 0;
+ qreal dragMinBound = 0;
+ qreal dragMaxBound = 0;
+ qreal previousDragDelta = 0;
+ qreal velocity = 0;
+ qreal flickTarget = 0;
+ qreal startMargin = 0;
+ qreal endMargin = 0;
+ qreal origin = 0;
+ qreal overshoot = 0;
+ qreal transitionTo = 0;
+ qreal continuousFlickVelocity = 0;
QElapsedTimer velocityTime;
- int vTime;
+ int vTime = 0;
QQuickFlickablePrivate::Velocity smoothVelocity;
QPODVector<qreal,10> velocityBuffer;
+ // bitfield
uint atEnd : 1;
uint atBeginning : 1;
uint transitionToSet : 1;
@@ -133,10 +128,11 @@ public:
uint dragging : 1;
uint extentsChanged : 1;
uint explicitValue : 1;
+ uint contentPositionChangedExternallyDuringDrag : 1;
+ // mutable portion of bitfield
mutable uint minExtentDirty : 1;
mutable uint maxExtentDirty : 1;
- uint contentPositionChangedExternallyDuringDrag : 1;
- uint unused : 17;
+ // end bitfield
};
bool flickX(QEvent::Type eventType, qreal velocity);
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 3aaa59819c..3efe082332 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -218,7 +218,7 @@ QQuickImage::~QQuickImage()
void QQuickImagePrivate::setImage(const QImage &image)
{
Q_Q(QQuickImage);
- pix.setImage(image);
+ currentPix->setImage(image);
q->pixmapChange();
q->update();
}
@@ -226,7 +226,7 @@ void QQuickImagePrivate::setImage(const QImage &image)
void QQuickImagePrivate::setPixmap(const QQuickPixmap &pixmap)
{
Q_Q(QQuickImage);
- pix.setPixmap(pixmap);
+ currentPix->setPixmap(pixmap);
q->pixmapChange();
q->update();
}
@@ -605,12 +605,12 @@ void QQuickImage::updatePaintedGeometry()
Q_D(QQuickImage);
if (d->fillMode == PreserveAspectFit) {
- if (!d->pix.width() || !d->pix.height()) {
+ if (!d->currentPix->width() || !d->currentPix->height()) {
setImplicitSize(0, 0);
return;
}
- const qreal pixWidth = d->pix.width() / d->devicePixelRatio;
- const qreal pixHeight = d->pix.height() / d->devicePixelRatio;
+ const qreal pixWidth = d->currentPix->width() / d->devicePixelRatio;
+ const qreal pixHeight = d->currentPix->height() / d->devicePixelRatio;
const qreal w = widthValid() ? width() : pixWidth;
const qreal widthScale = w / pixWidth;
const qreal h = heightValid() ? height() : pixHeight;
@@ -627,10 +627,10 @@ void QQuickImage::updatePaintedGeometry()
setImplicitSize(iWidth, iHeight);
} else if (d->fillMode == PreserveAspectCrop) {
- if (!d->pix.width() || !d->pix.height())
+ if (!d->currentPix->width() || !d->currentPix->height())
return;
- const qreal pixWidth = d->pix.width() / d->devicePixelRatio;
- const qreal pixHeight = d->pix.height() / d->devicePixelRatio;
+ const qreal pixWidth = d->currentPix->width() / d->devicePixelRatio;
+ const qreal pixHeight = d->currentPix->height() / d->devicePixelRatio;
qreal widthScale = width() / pixWidth;
qreal heightScale = height() / pixHeight;
if (widthScale < heightScale) {
@@ -642,8 +642,8 @@ void QQuickImage::updatePaintedGeometry()
d->paintedHeight = heightScale * pixHeight;
d->paintedWidth = widthScale * pixWidth;
} else if (d->fillMode == Pad) {
- d->paintedWidth = d->pix.width() / d->devicePixelRatio;
- d->paintedHeight = d->pix.height() / d->devicePixelRatio;
+ d->paintedWidth = d->currentPix->width() / d->devicePixelRatio;
+ d->paintedHeight = d->currentPix->height() / d->devicePixelRatio;
} else {
d->paintedWidth = width();
d->paintedHeight = height();
@@ -685,7 +685,7 @@ QSGTextureProvider *QQuickImage::textureProvider() const
dd->provider = new QQuickImageTextureProvider;
dd->provider->m_smooth = d->smooth;
dd->provider->m_mipmap = d->mipmap;
- dd->provider->updateTexture(d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window()));
+ dd->provider->updateTexture(d->sceneGraphRenderContext()->textureForFactory(d->currentPix->textureFactory(), window()));
}
return d->provider;
@@ -711,7 +711,7 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
Q_D(QQuickImage);
- QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window());
+ QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->currentPix->textureFactory(), window());
// Copy over the current texture state into the texture provider...
if (d->provider) {
@@ -736,8 +736,8 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
QSGTexture::WrapMode hWrap = QSGTexture::ClampToEdge;
QSGTexture::WrapMode vWrap = QSGTexture::ClampToEdge;
- qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->pix.width() / d->devicePixelRatio;
- qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight : d->pix.height() / d->devicePixelRatio;
+ qreal pixWidth = (d->fillMode == PreserveAspectFit) ? d->paintedWidth : d->currentPix->width() / d->devicePixelRatio;
+ qreal pixHeight = (d->fillMode == PreserveAspectFit) ? d->paintedHeight : d->currentPix->height() / d->devicePixelRatio;
int xOffset = 0;
if (d->hAlign == QQuickImage::AlignHCenter)
@@ -754,36 +754,36 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
switch (d->fillMode) {
case Stretch:
targetRect = QRectF(0, 0, width(), height());
- sourceRect = d->pix.rect();
+ sourceRect = d->currentPix->rect();
break;
case PreserveAspectFit:
targetRect = QRectF(xOffset, yOffset, d->paintedWidth, d->paintedHeight);
- sourceRect = d->pix.rect();
+ sourceRect = d->currentPix->rect();
break;
case PreserveAspectCrop: {
targetRect = QRectF(0, 0, width(), height());
- qreal wscale = width() / qreal(d->pix.width());
- qreal hscale = height() / qreal(d->pix.height());
+ qreal wscale = width() / qreal(d->currentPix->width());
+ qreal hscale = height() / qreal(d->currentPix->height());
if (wscale > hscale) {
- int src = (hscale / wscale) * qreal(d->pix.height());
+ int src = (hscale / wscale) * qreal(d->currentPix->height());
int y = 0;
if (d->vAlign == QQuickImage::AlignVCenter)
- y = qCeil((d->pix.height() - src) / 2.);
+ y = qCeil((d->currentPix->height() - src) / 2.);
else if (d->vAlign == QQuickImage::AlignBottom)
- y = qCeil(d->pix.height() - src);
- sourceRect = QRectF(0, y, d->pix.width(), src);
+ y = qCeil(d->currentPix->height() - src);
+ sourceRect = QRectF(0, y, d->currentPix->width(), src);
} else {
- int src = (wscale / hscale) * qreal(d->pix.width());
+ int src = (wscale / hscale) * qreal(d->currentPix->width());
int x = 0;
if (d->hAlign == QQuickImage::AlignHCenter)
- x = qCeil((d->pix.width() - src) / 2.);
+ x = qCeil((d->currentPix->width() - src) / 2.);
else if (d->hAlign == QQuickImage::AlignRight)
- x = qCeil(d->pix.width() - src);
- sourceRect = QRectF(x, 0, src, d->pix.height());
+ x = qCeil(d->currentPix->width() - src);
+ sourceRect = QRectF(x, 0, src, d->currentPix->height());
}
}
break;
@@ -797,13 +797,13 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
case TileHorizontally:
targetRect = QRectF(0, 0, width(), height());
- sourceRect = QRectF(-xOffset, 0, width(), d->pix.height());
+ sourceRect = QRectF(-xOffset, 0, width(), d->currentPix->height());
hWrap = QSGTexture::Repeat;
break;
case TileVertically:
targetRect = QRectF(0, 0, width(), height());
- sourceRect = QRectF(0, -yOffset, d->pix.width(), height());
+ sourceRect = QRectF(0, -yOffset, d->currentPix->width(), height());
vWrap = QSGTexture::Repeat;
break;
@@ -817,8 +817,8 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
break;
}
- qreal nsWidth = (hWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.width() / d->devicePixelRatio : d->pix.width();
- qreal nsHeight = (vWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->pix.height() / d->devicePixelRatio : d->pix.height();
+ qreal nsWidth = (hWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->currentPix->width() / d->devicePixelRatio : d->currentPix->width();
+ qreal nsHeight = (vWrap == QSGTexture::Repeat || d->fillMode == Pad) ? d->currentPix->height() / d->devicePixelRatio : d->currentPix->height();
QRectF nsrect(sourceRect.x() / nsWidth,
sourceRect.y() / nsHeight,
sourceRect.width() / nsWidth,
@@ -967,6 +967,25 @@ void QQuickImage::setMipmap(bool use)
frameCount is the number of frames in the image. Most images have only one frame.
*/
+/*!
+ \qmlproperty bool QtQuick::Image::retainWhileLoading
+ \since 6.8
+
+//! [qml-image-retainwhileloading]
+ This property defines the behavior when the \l source property is changed and loading happens
+ asynchronously. This is the case when the \l asynchronous property is set to \c true, or if the
+ image is not on the local file system.
+
+ If \c retainWhileLoading is \c false (the default), the old image is discarded immediately, and
+ the component is cleared while the new image is being loaded. If set to \c true, the old image
+ is retained and remains visible until the new one is ready.
+
+ Enabling this property can avoid flickering in cases where loading the new image takes a long
+ time. It comes at the cost of some extra memory use for double buffering while the new image is
+ being loaded.
+//! [qml-image-retainwhileloading]
+ */
+
QT_END_NAMESPACE
#include "moc_qquickimage_p_p.cpp"
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index bcc685d64c..581f119974 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -135,7 +135,7 @@ QSize QQuickImageBase::sourceSize() const
int width = d->sourcesize.width();
int height = d->sourcesize.height();
- return QSize(width != -1 ? width : d->pix.width(), height != -1 ? height : d->pix.height());
+ return QSize(width != -1 ? width : d->currentPix->width(), height != -1 ? height : d->currentPix->height());
}
void QQuickImageBase::resetSourceSize()
@@ -188,7 +188,7 @@ void QQuickImageBase::setCache(bool cache)
QImage QQuickImageBase::image() const
{
Q_D(const QQuickImageBase);
- return d->pix.image();
+ return d->currentPix->image();
}
void QQuickImageBase::setMirror(bool mirror)
@@ -234,7 +234,7 @@ bool QQuickImageBase::mirrorVertically() const
void QQuickImageBase::setCurrentFrame(int frame)
{
Q_D(QQuickImageBase);
- if (frame == d->currentFrame || frame < 0 || (isComponentComplete() && frame >= d->pix.frameCount()))
+ if (frame == d->currentFrame || frame < 0 || (isComponentComplete() && frame >= d->currentPix->frameCount()))
return;
d->currentFrame = frame;
@@ -264,7 +264,8 @@ int QQuickImageBase::frameCount() const
void QQuickImageBase::loadEmptyUrl()
{
Q_D(QQuickImageBase);
- d->pix.clear(this);
+ d->currentPix->clear(this);
+ d->pendingPix->clear(this);
d->setProgress(0);
d->status = Null; // do not emit statusChanged until after setImplicitSize
setImplicitSize(0, 0); // also called in QQuickImageBase::pixmapChange, but not QQuickImage/QQuickBorderImage overrides
@@ -290,7 +291,7 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
options |= QQuickPixmap::Asynchronous;
if (d->cache)
options |= QQuickPixmap::Cache;
- d->pix.clear(this);
+ d->pendingPix->clear(this);
QUrl loadUrl = url;
const QQmlContext *context = qmlContext(this);
if (context)
@@ -315,16 +316,18 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
d->status = Null; // reset status, no emit
- d->pix.load(qmlEngine(this),
- loadUrl,
- d->sourceClipRect.toRect(),
- (loadOptions & HandleDPR) ? d->sourcesize * d->devicePixelRatio : QSize(),
- options,
- (loadOptions & UseProviderOptions) ? d->providerOptions : QQuickImageProviderOptions(),
- d->currentFrame, d->frameCount,
- d->devicePixelRatio);
-
- if (d->pix.isLoading()) {
+ auto engine = qmlEngine(this);
+ if (engine) {
+ d->pendingPix->load(engine,
+ loadUrl,
+ d->sourceClipRect.toRect(),
+ (loadOptions & HandleDPR) ? d->sourcesize * d->devicePixelRatio : QSize(),
+ options,
+ (loadOptions & UseProviderOptions) ? d->providerOptions : QQuickImageProviderOptions(),
+ d->currentFrame, d->frameCount,
+ d->devicePixelRatio);
+ }
+ if (d->pendingPix->isLoading()) {
d->setProgress(0);
d->setStatus(Loading);
@@ -337,9 +340,10 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
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
+ d->pendingPix->connectFinished(this, thisRequestFinished);
+ d->pendingPix->connectDownloadProgress(this, thisRequestProgress);
+ if (!d->retainWhileLoading)
+ update(); //pixmap may have invalidated texture, updatePaintNode needs to be called before the next repaint
} else {
requestFinished();
}
@@ -360,10 +364,15 @@ void QQuickImageBase::load()
void QQuickImageBase::requestFinished()
{
Q_D(QQuickImageBase);
+ if (d->pendingPix != d->currentPix
+ && d->pendingPix->status() != QQuickPixmap::Null
+ && d->pendingPix->status() != QQuickPixmap::Loading) {
+ std::swap(d->pendingPix, d->currentPix);
+ d->pendingPix->clear(this); // Clear the old image
+ }
- if (d->pix.isError()) {
- qmlWarning(this) << d->pix.error();
- d->pix.clear(this);
+ if (d->currentPix->isError()) {
+ qmlWarning(this) << d->currentPix->error();
d->status = Error;
d->setProgress(0);
} else {
@@ -382,12 +391,12 @@ void QQuickImageBase::requestFinished()
d->oldAutoTransform = autoTransform();
emitAutoTransformBaseChanged();
}
- if (d->frameCount != d->pix.frameCount()) {
- d->frameCount = d->pix.frameCount();
+ if (d->frameCount != d->currentPix->frameCount()) {
+ d->frameCount = d->currentPix->frameCount();
emit frameCountChanged();
}
- if (d->colorSpace != d->pix.colorSpace()) {
- d->colorSpace = d->pix.colorSpace();
+ if (d->colorSpace != d->currentPix->colorSpace()) {
+ d->colorSpace = d->currentPix->colorSpace();
emit colorSpaceChanged();
}
@@ -430,7 +439,7 @@ void QQuickImageBase::componentComplete()
void QQuickImageBase::pixmapChange()
{
Q_D(QQuickImageBase);
- setImplicitSize(d->pix.width() / d->devicePixelRatio, d->pix.height() / d->devicePixelRatio);
+ setImplicitSize(d->currentPix->width() / d->devicePixelRatio, d->currentPix->height() / d->devicePixelRatio);
}
void QQuickImageBase::resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio)
@@ -470,7 +479,7 @@ bool QQuickImageBase::autoTransform() const
{
Q_D(const QQuickImageBase);
if (d->providerOptions.autoTransform() == QQuickImageProviderOptions::UsePluginDefaultTransform)
- return d->pix.autoTransform() == QQuickImageProviderOptions::ApplyTransform;
+ return d->currentPix->autoTransform() == QQuickImageProviderOptions::ApplyTransform;
return d->providerOptions.autoTransform() == QQuickImageProviderOptions::ApplyTransform;
}
@@ -500,6 +509,30 @@ void QQuickImageBase::setColorSpace(const QColorSpace &colorSpace)
emit colorSpaceChanged();
}
+bool QQuickImageBase::retainWhileLoading() const
+{
+ Q_D(const QQuickImageBase);
+ return d->retainWhileLoading;
+}
+
+void QQuickImageBase::setRetainWhileLoading(bool retainWhileLoading)
+{
+ Q_D(QQuickImageBase);
+ if (d->retainWhileLoading == retainWhileLoading)
+ return;
+
+ d->retainWhileLoading = retainWhileLoading;
+ if (d->retainWhileLoading) {
+ if (d->currentPix == &d->pix1)
+ d->pendingPix = &d->pix2;
+ else
+ d->pendingPix = &d->pix1;
+ } else {
+ d->pendingPix->clear();
+ d->pendingPix = d->currentPix;
+ }
+}
+
QT_END_NAMESPACE
#include "moc_qquickimagebase_p.cpp"
diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h
index 08f9abbc63..5a33db43b8 100644
--- a/src/quick/items/qquickimagebase_p.h
+++ b/src/quick/items/qquickimagebase_p.h
@@ -33,6 +33,7 @@ class Q_QUICK_EXPORT QQuickImageBase : public QQuickImplicitSizeItem
Q_PROPERTY(bool cache READ cache WRITE setCache NOTIFY cacheChanged)
Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged)
Q_PROPERTY(bool mirrorVertically READ mirrorVertically WRITE setMirrorVertically NOTIFY mirrorVerticallyChanged REVISION(6, 2))
+ Q_PROPERTY(bool retainWhileLoading READ retainWhileLoading WRITE setRetainWhileLoading NOTIFY retainWhileLoadingChanged REVISION(6, 8))
Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged REVISION(2, 14))
Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged REVISION(2, 14))
Q_PROPERTY(QColorSpace colorSpace READ colorSpace WRITE setColorSpace NOTIFY colorSpaceChanged REVISION(2, 15))
@@ -94,6 +95,9 @@ public:
QColorSpace colorSpace() const;
virtual void setColorSpace(const QColorSpace &colorSpace);
+ bool retainWhileLoading() const;
+ void setRetainWhileLoading(bool retain);
+
static void resolve2xLocalFile(const QUrl &url, qreal targetDevicePixelRatio, QUrl *sourceUrl, qreal *sourceDevicePixelRatio);
// Use a virtual rather than a signal->signal to avoid the huge
@@ -113,6 +117,7 @@ Q_SIGNALS:
Q_REVISION(2, 15) void sourceClipRectChanged();
Q_REVISION(2, 15) void colorSpaceChanged();
Q_REVISION(6, 2) void mirrorVerticallyChanged();
+ Q_REVISION(6, 8) void retainWhileLoadingChanged();
protected:
void loadEmptyUrl();
diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h
index 3cbb9facb0..d53712b779 100644
--- a/src/quick/items/qquickimagebase_p_p.h
+++ b/src/quick/items/qquickimagebase_p_p.h
@@ -33,8 +33,11 @@ public:
cache(true),
mirrorHorizontally(false),
mirrorVertically(false),
- oldAutoTransform(false)
+ oldAutoTransform(false),
+ retainWhileLoading(false)
{
+ pendingPix = &pix1;
+ currentPix = &pix1;
}
virtual bool updateDevicePixelRatio(qreal targetDevicePixelRatio);
@@ -43,7 +46,10 @@ public:
void setProgress(qreal value);
QUrl url;
- QQuickPixmap pix;
+ QQuickPixmap *pendingPix = nullptr;
+ QQuickPixmap *currentPix = nullptr;
+ QQuickPixmap pix1;
+ QQuickPixmap pix2;
QSize sourcesize;
QSize oldSourceSize;
QRectF sourceClipRect;
@@ -61,6 +67,7 @@ public:
bool mirrorHorizontally: 1;
bool mirrorVertically : 1;
bool oldAutoTransform : 1;
+ bool retainWhileLoading : 1;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index e7b2a31f04..6c4ab28768 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -57,13 +57,9 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcMouseTarget)
-Q_DECLARE_LOGGING_CATEGORY(lcHoverTrace)
-Q_DECLARE_LOGGING_CATEGORY(lcPtr)
-Q_DECLARE_LOGGING_CATEGORY(lcTransient)
Q_LOGGING_CATEGORY(lcHandlerParent, "qt.quick.handler.parent")
Q_LOGGING_CATEGORY(lcVP, "qt.quick.viewport")
-Q_LOGGING_CATEGORY(lcChangeListeners, "qt.quick.item.changelisteners")
+Q_STATIC_LOGGING_CATEGORY(lcChangeListeners, "qt.quick.item.changelisteners")
// after 100ms, a mouse/non-mouse cursor conflict is resolved in favor of the mouse handler
static const quint64 kCursorOverrideTimeout = 100;
@@ -1744,12 +1740,13 @@ Qt::FocusReason QQuickItemPrivate::lastFocusChangeReason() const
return static_cast<Qt::FocusReason>(focusReason);
}
-void QQuickItemPrivate::setLastFocusChangeReason(Qt::FocusReason reason)
+bool QQuickItemPrivate::setLastFocusChangeReason(Qt::FocusReason reason)
{
if (focusReason == reason)
- return;
+ return false;
focusReason = reason;
+ return true;
}
/*!
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index bb238904ca..8c99d0656c 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -48,6 +48,9 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcHandlerParent)
+Q_DECLARE_LOGGING_CATEGORY(lcVP)
+
class QNetworkReply;
class QQuickItemKeyFilter;
class QQuickLayoutMirroringAttached;
@@ -564,7 +567,7 @@ public:
bool setFocusIfNeeded(QEvent::Type);
Qt::FocusReason lastFocusChangeReason() const;
- void setLastFocusChangeReason(Qt::FocusReason reason);
+ virtual bool setLastFocusChangeReason(Qt::FocusReason reason);
QTransform windowToItemTransform() const;
QTransform itemToWindowTransform() const;
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 569a0ad74d..d08c43ed22 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -85,10 +85,6 @@
#include "handlers/qquicktaphandler_p.h"
#include "handlers/qquickwheelhandler_p.h"
-QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcTransient)
-QT_END_NAMESPACE
-
#include "moc_qquickitemsmodule_p.cpp"
static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject *parent)
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 70d460a323..1518a484d3 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -1086,8 +1086,7 @@ qreal QQuickItemViewPrivate::calculatedMaxExtent() const
void QQuickItemViewPrivate::applyDelegateChange()
{
releaseVisibleItems(QQmlDelegateModel::NotReusable);
- releaseItem(currentItem, QQmlDelegateModel::NotReusable);
- currentItem = nullptr;
+ releaseCurrentItem(QQmlDelegateModel::NotReusable);
updateSectionCriteria();
refill();
moveReason = QQuickItemViewPrivate::SetIndex;
@@ -1654,8 +1653,7 @@ void QQuickItemViewPrivate::updateCurrent(int modelIndex)
if (currentItem) {
if (currentItem->attached)
currentItem->attached->setIsCurrentItem(false);
- releaseItem(currentItem, reusableFlag);
- currentItem = nullptr;
+ releaseCurrentItem(reusableFlag);
currentIndex = modelIndex;
emit q->currentIndexChanged();
emit q->currentItemChanged();
@@ -1716,10 +1714,9 @@ void QQuickItemViewPrivate::clear(bool onDestruction)
releasePendingTransition.clear();
#endif
- auto oldCurrentItem = currentItem;
- releaseItem(currentItem, QQmlDelegateModel::NotReusable);
- currentItem = nullptr;
- if (oldCurrentItem)
+ const bool hadCurrentItem = currentItem != nullptr;
+ releaseCurrentItem(QQmlDelegateModel::NotReusable);
+ if (hadCurrentItem)
emit q->currentItemChanged();
createHighlight(onDestruction);
trackedItem = nullptr;
@@ -2123,10 +2120,9 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult
if (currentChanges.currentRemoved && currentItem) {
if (currentItem->item && currentItem->attached)
currentItem->attached->setIsCurrentItem(false);
- auto oldCurrentItem = currentItem;
- releaseItem(currentItem, reusableFlag);
- currentItem = nullptr;
- if (oldCurrentItem)
+ const bool hadCurrentItem = currentItem != nullptr;
+ releaseCurrentItem(reusableFlag);
+ if (hadCurrentItem)
emit q->currentItemChanged();
}
if (!currentIndexCleared)
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index c05233d82a..0179dc1fdd 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -145,6 +145,11 @@ public:
void mirrorChange() override;
FxViewItem *createItem(int modelIndex,QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested);
+ bool releaseCurrentItem(QQmlInstanceModel::ReusableFlag reusableFlag)
+ {
+ auto oldCurrentItem = std::exchange(currentItem, nullptr);
+ return releaseItem(oldCurrentItem, reusableFlag);
+ }
virtual bool releaseItem(FxViewItem *item, QQmlInstanceModel::ReusableFlag reusableFlag);
QQuickItem *createHighlightItem() const;
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 6b185b4e7c..ecc3832a4a 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -22,7 +22,7 @@ QT_BEGIN_NAMESPACE
#define QML_FLICK_SNAPONETHRESHOLD 30
#endif
-Q_LOGGING_CATEGORY(lcEvents, "qt.quick.listview.events")
+Q_STATIC_LOGGING_CATEGORY(lcEvents, "qt.quick.listview.events")
class FxListItemSG;
@@ -3792,7 +3792,10 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
continue;
}
- visibleItems.insert(index, item);
+ if (index < visibleItems.size())
+ visibleItems.insert(index, item);
+ else // special case of appending an item to the model - as above
+ visibleItems.append(item);
if (index == 0)
insertResult->changedFirstItem = true;
if (change.isMove()) {
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 15cf20ea7a..496948fcb7 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -13,8 +13,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcTransient)
-
static const QQuickItemPrivate::ChangeTypes watchedChanges
= QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index a6edfc4754..7e68dd8be3 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -21,8 +21,6 @@ QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlMaVisualTouchDebugging, QML_VISUAL_TOUCH_DEBUGGING)
-Q_DECLARE_LOGGING_CATEGORY(lcHoverTrace)
-
QQuickMouseAreaPrivate::QQuickMouseAreaPrivate()
: enabled(true), hoverEnabled(false), scrollGestureEnabled(true), hovered(false), longPress(false),
moved(false), stealMouse(false), doubleClick(false), preventStealing(false),
diff --git a/src/quick/items/qquickpalettecolorprovider.cpp b/src/quick/items/qquickpalettecolorprovider.cpp
index af6f0ef7a5..f01fa22bdd 100644
--- a/src/quick/items/qquickpalettecolorprovider.cpp
+++ b/src/quick/items/qquickpalettecolorprovider.cpp
@@ -162,6 +162,7 @@ bool QQuickPaletteColorProvider::doInheritPalette(const QPalette &palette)
{
auto inheritedMask = m_requestedPalette.isAllocated() ? m_requestedPalette->resolveMask() | palette.resolveMask()
: palette.resolveMask();
+ // If a palette was set on this item, it should always win over the palette to be inherited from.
QPalette parentPalette = m_requestedPalette.isAllocated() ? m_requestedPalette->resolve(palette) : palette;
parentPalette.setResolveMask(inheritedMask);
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index ce61543f42..3fc7de987c 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -23,13 +23,16 @@
#include <cmath>
+#if QT_CONFIG(quick_itemview)
+#include <private/qquickitemview_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcItemViewDelegateLifecycle)
#if !QT_CONFIG(quick_itemview)
-Q_LOGGING_CATEGORY(lcItemViewDelegateLifecycle, "qt.quick.itemview.lifecycle")
+Q_STATIC_LOGGING_CATEGORY(lcItemViewDelegateLifecycle, "qt.quick.itemview.lifecycle")
#endif
-Q_LOGGING_CATEGORY(lcPathView, "qt.quick.pathview")
+Q_STATIC_LOGGING_CATEGORY(lcPathView, "qt.quick.pathview")
static QQmlOpenMetaObjectType *qPathViewAttachedType = nullptr;
@@ -209,10 +212,7 @@ QQmlOpenMetaObjectType *QQuickPathViewPrivate::attachedType()
void QQuickPathViewPrivate::clear()
{
- if (currentItem) {
- releaseItem(currentItem);
- currentItem = nullptr;
- }
+ releaseCurrentItem();
for (QQuickItem *p : std::as_const(items))
releaseItem(p);
@@ -738,14 +738,13 @@ void QQuickPathView::setCurrentIndex(int idx)
? ((idx % d->modelCount) + d->modelCount) % d->modelCount
: 0;
if (d->model && (idx != d->currentIndex || !d->currentItem)) {
- if (d->currentItem) {
+ const bool hadCurrentItem = d->currentItem != nullptr;
+ const int oldCurrentIdx = d->currentIndex;
+ if (hadCurrentItem) {
if (QQuickPathViewAttached *att = d->attached(d->currentItem))
att->setIsCurrentItem(false);
- d->releaseItem(d->currentItem);
+ d->releaseCurrentItem();
}
- int oldCurrentIdx = d->currentIndex;
- QQuickItem *oldCurrentItem = d->currentItem;
- d->currentItem = nullptr;
d->moveReason = QQuickPathViewPrivate::SetIndex;
d->currentIndex = idx;
if (d->modelCount) {
@@ -757,7 +756,7 @@ void QQuickPathView::setCurrentIndex(int idx)
}
if (oldCurrentIdx != d->currentIndex)
emit currentIndexChanged();
- if (oldCurrentItem != d->currentItem)
+ if (hadCurrentItem)
emit currentItemChanged();
}
}
@@ -2208,8 +2207,7 @@ void QQuickPathView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
} else if (d->currentItem) {
if (QQuickPathViewAttached *att = d->attached(d->currentItem))
att->setIsCurrentItem(true);
- d->releaseItem(d->currentItem);
- d->currentItem = nullptr;
+ d->releaseCurrentItem();
}
d->currentIndex = qMin(r.index, d->modelCount - r.count - 1);
currentChanged = true;
@@ -2357,7 +2355,7 @@ void QQuickPathViewPrivate::updateCurrent()
if (currentItem) {
if (QQuickPathViewAttached *att = attached(currentItem))
att->setIsCurrentItem(false);
- releaseItem(currentItem);
+ releaseCurrentItem();
}
int oldCurrentIndex = currentIndex;
currentIndex = idx;
diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h
index 3b7487afbf..f23b03f6c2 100644
--- a/src/quick/items/qquickpathview_p_p.h
+++ b/src/quick/items/qquickpathview_p_p.h
@@ -69,6 +69,11 @@ public:
}
QQuickItem *getItem(int modelIndex, qreal z = 0, bool async=false);
+ void releaseCurrentItem()
+ {
+ auto oldCurrentItem = std::exchange(currentItem, nullptr);
+ releaseItem(oldCurrentItem);
+ }
void releaseItem(QQuickItem *item);
QQuickPathViewAttached *attached(QQuickItem *item);
QQmlOpenMetaObjectType *attachedType();
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index 482941b9ba..b9e597a789 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -17,7 +17,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcPA, "qt.quick.pincharea")
+Q_STATIC_LOGGING_CATEGORY(lcPA, "qt.quick.pincharea")
/*!
\qmltype PinchEvent
diff --git a/src/quick/items/qquickrendertarget.cpp b/src/quick/items/qquickrendertarget.cpp
index bce5b358ff..55bbf22eee 100644
--- a/src/quick/items/qquickrendertarget.cpp
+++ b/src/quick/items/qquickrendertarget.cpp
@@ -226,7 +226,7 @@ void QQuickRenderTarget::setDepthTexture(QRhiTexture *texture)
\enum QQuickRenderTarget::Flag
Flags for the static QQuickRenderTarget constructor functions.
- \value MultisampleResolve Indicates the the \c sampleCount argument is not
+ \value MultisampleResolve Indicates that the \c sampleCount argument is not
the number of samples for the provided texture (and that the texture is
still a non-multisample texture), but rather the desired samples for
multisample antialiasing. Triggers automatically creating and managing an
@@ -1445,7 +1445,8 @@ static bool createRhiRenderTargetWithDepthTexture(QRhiTexture *texture,
return false;
}
if (needsDepthStencilBuffer && !depthStencil) {
- depthStencil.reset(rhi->newTexture(QRhiTexture::D24S8, pixelSize, sampleCount, QRhiTexture::RenderTarget));
+ QRhiTexture::Format multisampleDepthTextureFormat = depthTexture->format();
+ depthStencil.reset(rhi->newTexture(multisampleDepthTextureFormat, pixelSize, sampleCount, QRhiTexture::RenderTarget));
depthStencil->setName(QByteArrayLiteral("Depth-stencil texture for QQuickRenderTarget"));
if (!depthStencil->create()) {
qWarning("Failed to build depth-stencil buffer for QQuickRenderTarget");
diff --git a/src/quick/items/qquickrhiitem.cpp b/src/quick/items/qquickrhiitem.cpp
index 69b6bb15ed..b83df7f33a 100644
--- a/src/quick/items/qquickrhiitem.cpp
+++ b/src/quick/items/qquickrhiitem.cpp
@@ -114,8 +114,22 @@ QT_BEGIN_NAMESPACE
\snippet qquickrhiitem/qquickrhiitem_intro.cpp 0
It is notable that this simple class is almost exactly the same as the code
- shown in the \l QRhiWidget introduction. The vertex and fragment shaders
- are the same as shown there.
+ shown in the \l QRhiWidget introduction. The vertex and fragment shaders are
+ the same as well. These are provided as Vulkan-style GLSL source code and
+ must be processed first by the Qt shader infrastructure first. This is
+ achieved either by running the \c qsb command-line tool manually, or by
+ using the \l{Qt Shader Tools Build System Integration}{qt_add_shaders()}
+ function in CMake. The QQuickRhiItem loads these pre-processed \c{.qsb}
+ files that are shipped with the application. See \l{Qt Shader Tools} for
+ more information about Qt's shader translation infrastructure.
+
+ \c{color.vert}
+
+ \snippet qquickrhiitem/qquickrhiitem_intro.vert 0
+
+ \c{color.frag}
+
+ \snippet qquickrhiitem/qquickrhiitem_intro.frag 0
Once exposed to QML (note the \c QML_NAMED_ELEMENT), our custom item can be
instantiated in any scene. (after importing the appropriate \c URI specified
@@ -125,7 +139,7 @@ QT_BEGIN_NAMESPACE
ExampleRhiItem {
anchors.fill: parent
anchors.margins: 10
- NumberAnimation on angle { from: 0; to: 360: duration: 5000; loops: Animation.Infinite }
+ NumberAnimation on angle { from: 0; to: 360; duration: 5000; loops: Animation.Infinite }
}
\endcode
@@ -905,7 +919,7 @@ QRhi *QQuickRhiItemRenderer::rhi() const
Unlike the depth-stencil buffer and the QRhiRenderTarget, this texture is
always available and is managed by the QQuickRhiItem, independent of the
- value of \l {QQuickRhiItem::}{autoRenderTarget}.
+ value of \l {QQuickRhiItem::}{isAutoRenderTargetEnabled}.
\note When \l {QQuickRhiItem::}{sampleCount} is larger than 1, and so
multisample antialiasing is enabled, the return value is \nullptr. Instead,
@@ -930,12 +944,12 @@ QRhiTexture *QQuickRhiItemRenderer::colorTexture() const
When \l {QQuickRhiItem::}{sampleCount} is larger than 1, and so multisample
antialising is enabled, the returned QRhiRenderBuffer has a matching sample
- count and serves as the color buffer. Graphics pipelines used to render into
- this buffer must be created with the same sample count, and the
+ count and serves as the color buffer. Graphics pipelines used to render
+ into this buffer must be created with the same sample count, and the
depth-stencil buffer's sample count must match as well. The multisample
content is expected to be resolved into the texture returned from
- resolveTexture(). When \l {QQuickRhiItem::}{autoRenderTarget} is \c true,
- renderTarget() is set up automatically to do this, by setting up
+ resolveTexture(). When \l {QQuickRhiItem::}{isAutoRenderTargetEnabled} is
+ \c true, renderTarget() is set up automatically to do this, by setting up
msaaColorBuffer() as the
\l{QRhiColorAttachment::renderBuffer()}{renderbuffer} of color attachment 0
and resolveTexture() as its
@@ -975,11 +989,11 @@ QRhiRenderBuffer *QQuickRhiItemRenderer::msaaColorBuffer() const
With MSAA enabled, this is the texture that gets used by the item's
underlying scene graph node when texturing a quad in the main render pass
of Qt Quick. However, the QQuickRhiItemRenderer's rendering must target the
- (multisample) QRhiRenderBuffer returned from msaaColorBuffer(). When
- \l {QQuickRhiItem::}{autoRenderTarget} is \c true, this is taken care of by
- the QRhiRenderTarget returned from renderTarget(). Otherwise, it is up to
- the subclass code to correctly configure a render target object with both
- the color buffer and resolve textures.
+ (multisample) QRhiRenderBuffer returned from msaaColorBuffer(). When \l
+ {QQuickRhiItem::}{isAutoRenderTargetEnabled} is \c true, this is taken care
+ of by the QRhiRenderTarget returned from renderTarget(). Otherwise, it is
+ up to the subclass code to correctly configure a render target object with
+ both the color buffer and resolve textures.
\sa colorTexture()
*/
@@ -993,10 +1007,10 @@ QRhiTexture *QQuickRhiItemRenderer::resolveTexture() const
Must only be called from initialize() and render().
- Available only when \l {QQuickRhiItem::}{autoRenderTarget} is \c true.
- Otherwise the returned value is \nullptr and it is up the reimplementation
- of initialize() to create and manage a depth-stencil buffer and a
- QRhiTextureRenderTarget.
+ Available only when \l {QQuickRhiItem::}{isAutoRenderTargetEnabled} is \c
+ true. Otherwise the returned value is \nullptr and it is up the
+ reimplementation of initialize() to create and manage a depth-stencil
+ buffer and a QRhiTextureRenderTarget.
\sa colorTexture(), renderTarget()
*/
@@ -1011,10 +1025,10 @@ QRhiRenderBuffer *QQuickRhiItemRenderer::depthStencilBuffer() const
Must only be called from initialize() and render().
- Available only when \l {QQuickRhiItem::}{autoRenderTarget} is \c true.
- Otherwise the returned value is \nullptr and it is up the reimplementation
- of initialize() to create and manage a depth-stencil buffer and a
- QRhiTextureRenderTarget.
+ Available only when \l {QQuickRhiItem::}{isAutoRenderTargetEnabled} is \c
+ true. Otherwise the returned value is \nullptr and it is up the
+ reimplementation of initialize() to create and manage a depth-stencil
+ buffer and a QRhiTextureRenderTarget.
When creating \l{QRhiGraphicsPipeline}{graphics pipelines}, a
QRhiRenderPassDescriptor is needed. This can be queried from the returned
@@ -1076,14 +1090,14 @@ QRhiRenderTarget *QQuickRhiItemRenderer::renderTarget() const
resources previously created by the subclass are destroyed because they
belong to the previous QRhi that should not be used anymore.
- When \l {QQuickRhiItem::}{autoRenderTarget} is \c true, which is the
- default, a depth-stencil QRhiRenderBuffer and a QRhiTextureRenderTarget
+ When \l {QQuickRhiItem::}{isAutoRenderTargetEnabled} is \c true, which is
+ the default, a depth-stencil QRhiRenderBuffer and a QRhiTextureRenderTarget
associated with the colorTexture() (or msaaColorBuffer()) and the
depth-stencil buffer are created and managed automatically.
Reimplementations of initialize() and render() can query those objects via
- depthStencilBuffer() and renderTarget(). When
- \l {QQuickRhiItem::}{autoRenderTarget} is set to \c false, these objects are
- no longer created and managed automatically. Rather, it will be
+ depthStencilBuffer() and renderTarget(). When \l
+ {QQuickRhiItem::}{isAutoRenderTargetEnabled} is set to \c false, these
+ objects are no longer created and managed automatically. Rather, it will be
up the the initialize() implementation to create buffers and set up the
render target as it sees fit. When manually managing additional color or
depth-stencil attachments for the render target, their size and sample
diff --git a/src/quick/items/qquickselectable_p.h b/src/quick/items/qquickselectable_p.h
index dbee64c49e..65434be490 100644
--- a/src/quick/items/qquickselectable_p.h
+++ b/src/quick/items/qquickselectable_p.h
@@ -37,7 +37,7 @@ public:
virtual void normalizeSelection() = 0;
virtual QRectF selectionRectangle() const = 0;
- virtual QSizeF scrollTowardsSelectionPoint(const QPointF &pos, const QSizeF &step) = 0;
+ virtual QSizeF scrollTowardsPoint(const QPointF &pos, const QSizeF &step) = 0;
virtual void setCallback(std::function<void(CallBackFlag)> func) = 0;
};
diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp
index 35b29b9134..9541121f51 100644
--- a/src/quick/items/qquickstateoperations.cpp
+++ b/src/quick/items/qquickstateoperations.cpp
@@ -1062,17 +1062,24 @@ void QQuickAnchorChanges::reverse()
//restore any absolute geometry changed by the state's anchors
QQuickAnchors::Anchors stateVAnchors = d->anchorSet->d_func()->usedAnchors & QQuickAnchors::Vertical_Mask;
QQuickAnchors::Anchors origVAnchors = targetPrivate->anchors()->usedAnchors() & QQuickAnchors::Vertical_Mask;
+ QQuickAnchors::Anchors resetVAnchors = d->anchorSet->d_func()->resetAnchors & QQuickAnchors::Vertical_Mask;
QQuickAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QQuickAnchors::Horizontal_Mask;
QQuickAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QQuickAnchors::Horizontal_Mask;
+ QQuickAnchors::Anchors resetHAnchors = d->anchorSet->d_func()->resetAnchors & QQuickAnchors::Horizontal_Mask;
const QRectF oldGeometry(d->target->position(), d->target->size());
bool stateSetWidth = (stateHAnchors &&
stateHAnchors != QQuickAnchors::LeftAnchor &&
stateHAnchors != QQuickAnchors::RightAnchor &&
stateHAnchors != QQuickAnchors::HCenterAnchor);
- // in case of an additive AnchorChange, we _did_ end up modifying the width
- stateSetWidth |= ((stateHAnchors & QQuickAnchors::LeftAnchor) && (origHAnchors & QQuickAnchors::RightAnchor)) ||
- ((stateHAnchors & QQuickAnchors::RightAnchor) && (origHAnchors & QQuickAnchors::LeftAnchor));
+ // in case of an additive AnchorChange, we _did_ end up modifying the width, unless opposite
+ // edge was set to undefined in state
+ stateSetWidth |= ((stateHAnchors & QQuickAnchors::LeftAnchor)
+ && (origHAnchors & QQuickAnchors::RightAnchor)
+ && !(resetHAnchors & QQuickAnchors::RightAnchor))
+ || ((stateHAnchors & QQuickAnchors::RightAnchor)
+ && (origHAnchors & QQuickAnchors::LeftAnchor)
+ && !(resetHAnchors & QQuickAnchors::LeftAnchor));
bool origSetWidth = (origHAnchors &&
origHAnchors != QQuickAnchors::LeftAnchor &&
origHAnchors != QQuickAnchors::RightAnchor &&
@@ -1088,9 +1095,14 @@ void QQuickAnchorChanges::reverse()
stateVAnchors != QQuickAnchors::BottomAnchor &&
stateVAnchors != QQuickAnchors::VCenterAnchor &&
stateVAnchors != QQuickAnchors::BaselineAnchor);
- // in case of an additive AnchorChange, we _did_ end up modifying the height
- stateSetHeight |= ((stateVAnchors & QQuickAnchors::TopAnchor) && (origVAnchors & QQuickAnchors::BottomAnchor)) ||
- ((stateVAnchors & QQuickAnchors::BottomAnchor) && (origVAnchors & QQuickAnchors::TopAnchor));
+ // in case of an additive AnchorChange, we _did_ end up modifying the height, unless opposite
+ // edge was set to undefined in state
+ stateSetHeight |= ((stateVAnchors & QQuickAnchors::TopAnchor)
+ && (origVAnchors & QQuickAnchors::BottomAnchor)
+ && !(resetVAnchors & QQuickAnchors::BottomAnchor))
+ || ((stateVAnchors & QQuickAnchors::BottomAnchor)
+ && (origVAnchors & QQuickAnchors::TopAnchor)
+ && !(resetVAnchors & QQuickAnchors::TopAnchor));
bool origSetHeight = (origVAnchors &&
origVAnchors != QQuickAnchors::TopAnchor &&
origVAnchors != QQuickAnchors::BottomAnchor &&
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 6203f6f3c1..82e3ee7d6f 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -6,11 +6,13 @@
#include <QtCore/qtimer.h>
#include <QtCore/qdir.h>
+#include <QtCore/qmimedata.h>
#include <QtQmlModels/private/qqmldelegatemodel_p.h>
#include <QtQmlModels/private/qqmldelegatemodel_p_p.h>
#include <QtQml/private/qqmlincubator_p.h>
#include <QtQmlModels/private/qqmlchangeset_p.h>
#include <QtQml/qqmlinfo.h>
+#include <QtQuick/qquickitemgrabresult.h>
#include <QtQuick/private/qquickflickable_p_p.h>
#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
@@ -467,6 +469,9 @@
\li required property bool current - \c true if the delegate is \l {Keyboard navigation}{current.}
\li required property bool selected - \c true if the delegate is \l {Selecting items}{selected.}
\li required property bool editing - \c true if the delegate is being \l {Editing cells}{edited.}
+ \li required property bool containsDrag - \c true if a column or row is currently being dragged
+ over this delegate. This property is only supported for HorizontalHeaderView and
+ VerticalHeaderView. (since Qt 6.8)
\endlist
The following example shows how to use these properties:
@@ -944,6 +949,48 @@
*/
/*!
+ \qmlmethod QtQuick::TableView::moveColumn(int source, int destination)
+ \since 6.8
+
+ Moves a column from the \a source to the \a destination position.
+
+ \note If a syncView is set, the sync view will control the internal index mapping for
+ column reordering. Therefore, in that case, a call to this function will be forwarded to
+ the sync view instead.
+*/
+
+/*!
+ \qmlmethod QtQuick::TableView::clearColumnReordering()
+ \since 6.8
+
+ Resets any previously applied column reordering.
+
+ \note If a syncView is set, a call to this function will be forwarded to
+ corresponding view item and reset the column ordering.
+*/
+
+/*!
+ \qmlmethod QtQuick::TableView::moveRow(int source, int destination)
+ \since 6.8
+
+ Moves a row from the \a source to the \a destination position.
+
+ \note If a syncView is set, the sync view will control the internal index mapping for
+ row reordering. Therefore, in that case, a call to this function will be forwarded to
+ the sync view instead.
+*/
+
+/*!
+ \qmlmethod QtQuick::TableView::clearRowReordering()
+ \since 6.8
+
+ Resets any previously applied row reordering.
+
+ \note If a syncView is set, a call to this function will be forwarded to
+ the corresponding view item and reset the row ordering.
+*/
+
+/*!
\qmlmethod Item QtQuick::TableView::itemAtCell(point cell)
Returns the delegate item at \a cell if loaded, otherwise \c null.
@@ -1042,32 +1089,26 @@
\qmlmethod real QtQuick::TableView::implicitColumnWidth(int column)
\since 6.2
- Returns the implicit width of the given \a column. If the
- column is not loaded (and therefore not visible), the return value
- will be \c -1.
+ Returns the implicit width of the given \a column. This is the largest
+ \l implicitWidth found among the currently \l{isRowLoaded()}{loaded}
+ delegate items inside that column.
- The implicit width of a column is the largest implicitWidth
- found among the currently loaded delegate items inside that column.
- Widths returned by the \l columnWidthProvider will not be taken
- into account.
+ If the \a column is not loaded (and therefore not visible), the return value is \c -1.
- \sa columnWidthProvider, columnWidth(), isColumnLoaded(), {Row heights and column widths}
+ \sa columnWidth(), isRowLoaded(), {Row heights and column widths}
*/
/*!
\qmlmethod real QtQuick::TableView::implicitRowHeight(int row)
\since 6.2
- Returns the implicit height of the given \a row. If the
- row is not loaded (and therefore not visible), the return value
- will be \c -1.
+ Returns the implicit height of the given \a row. This is the largest
+ \l implicitHeight found among the currently \l{isColumnLoaded()}{loaded}
+ delegate items inside that row.
- The implicit height of a row is the largest implicitHeight
- found among the currently loaded delegate items inside that row.
- Heights returned by the \l rowHeightProvider will not be taken
- into account.
+ If the \a row is not loaded (and therefore not visible), the return value is \c -1.
- \sa rowHeightProvider, rowHeight(), isRowLoaded(), {Row heights and column widths}
+ \sa rowHeight(), isColumnLoaded(), {Row heights and column widths}
*/
/*!
@@ -1233,13 +1274,15 @@
Convenience function for doing:
\code
- modelIndex(cell.y, cell.x)
+ index(cell.y, cell.x)
\endcode
A \a cell is simply a \l point that combines row and column into
a single type.
\note \c {point.x} will map to the column, and \c {point.y} will map to the row.
+
+ \sa index()
*/
/*!
@@ -1339,6 +1382,24 @@
*/
/*!
+ \qmlsignal QtQuick::TableView::columnMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex)
+ \since 6.8
+
+ This signal is emitted when a column is moved. The column's logical index is specified by
+ \a logicalIndex, the old index by \a oldVisualIndex, and the new index position by
+ \a newVisualIndex.
+*/
+
+/*!
+ \qmlsignal QtQuick::TableView::rowMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex)
+ \since 6.8
+
+ This signal is emitted when a row is moved. The row's logical index is specified by
+ \a logicalIndex, the old index by \a oldVisualIndex, and the new index position by
+ \a newVisualIndex.
+*/
+
+/*!
\qmlattachedproperty TableView QtQuick::TableView::view
This attached property holds the view that manages the delegate instance.
@@ -1459,6 +1520,7 @@ static const char* kRequiredProperties = "_qt_tableview_requiredpropertymask";
static const char* kRequiredProperty_selected = "selected";
static const char* kRequiredProperty_current = "current";
static const char* kRequiredProperty_editing = "editing";
+static const char* kRequiredProperty_containsDrag = "containsDrag";
QDebug operator<<(QDebug dbg, QQuickTableViewPrivate::RebuildState state)
{
@@ -1682,9 +1744,12 @@ bool QQuickTableViewPrivate::startSelection(const QPointF &pos, Qt::KeyboardModi
if (resizeHandler->state() != QQuickTableViewResizeHandler::Listening)
return false;
- // For SingleSelection and ContiguousSelection, we should only allow one selection at a time
+ // For SingleSelection and ContiguousSelection, we should only allow one
+ // selection at a time. We also clear the current selection if the mode
+ // is ExtendedSelection, but no modifier is being held.
if (selectionMode == QQuickTableView::SingleSelection
- || selectionMode == QQuickTableView::ContiguousSelection)
+ || selectionMode == QQuickTableView::ContiguousSelection
+ || modifiers == Qt::NoModifier)
clearSelection();
else if (selectionModel)
existingSelection = selectionModel->selection();
@@ -1849,28 +1914,43 @@ void QQuickTableViewPrivate::updateSelection(const QRect &oldSelection, const QR
{
const QModelIndex startIndex = qaim->index(newRect.y(), newRect.x());
const QModelIndex endIndex = qaim->index(newRect.y() + newRect.height(), newRect.x() + newRect.width());
- select = QItemSelection(startIndex, endIndex);
+ for (const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
+ const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
+ select.append(QItemSelection(logicalModelIndex, logicalModelIndex));
+ }
}
// Unselect cells in the new minus old rects
if (oldRect.x() < newRect.x()) {
const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), newRect.x() - 1);
- deselect.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
+ for (const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
+ const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
+ deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
+ }
} else if (oldRect.x() + oldRect.width() > newRect.x() + newRect.width()) {
const QModelIndex startIndex = qaim->index(oldRect.y(), newRect.x() + newRect.width() + 1);
const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
- deselect.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
+ for (auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
+ const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
+ deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
+ }
}
if (oldRect.y() < newRect.y()) {
const QModelIndex startIndex = qaim->index(oldRect.y(), oldRect.x());
const QModelIndex endIndex = qaim->index(newRect.y() - 1, oldRect.x() + oldRect.width());
- deselect.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
+ for (const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
+ const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
+ deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
+ }
} else if (oldRect.y() + oldRect.height() > newRect.y() + newRect.height()) {
const QModelIndex startIndex = qaim->index(newRect.y() + newRect.height() + 1, oldRect.x());
const QModelIndex endIndex = qaim->index(oldRect.y() + oldRect.height(), oldRect.x() + oldRect.width());
- deselect.merge(QItemSelection(startIndex, endIndex), QItemSelectionModel::Select);
+ for (const auto &modelIndex : QItemSelection(startIndex, endIndex).indexes()) {
+ const QModelIndex &logicalModelIndex = qaim->index(logicalRowIndex(modelIndex.row()), logicalColumnIndex(modelIndex.column()));
+ deselect.merge(QItemSelection(logicalModelIndex, logicalModelIndex), QItemSelectionModel::Select);
+ }
}
if (selectionFlag == QItemSelectionModel::Select) {
@@ -1976,7 +2056,7 @@ QRect QQuickTableViewPrivate::selection() const
return QRect(selectionStartCell.x(), selectionStartCell.y(), w, h);
}
-QSizeF QQuickTableViewPrivate::scrollTowardsSelectionPoint(const QPointF &pos, const QSizeF &step)
+QSizeF QQuickTableViewPrivate::scrollTowardsPoint(const QPointF &pos, const QSizeF &step)
{
Q_Q(QQuickTableView);
@@ -2085,14 +2165,14 @@ QPoint QQuickTableViewPrivate::cellAtModelIndex(int modelIndex) const
}
}
-int QQuickTableViewPrivate::modelIndexToCellIndex(const QModelIndex &modelIndex) const
+int QQuickTableViewPrivate::modelIndexToCellIndex(const QModelIndex &modelIndex, bool visualIndex) const
{
// Convert QModelIndex to cell index. A cell index is just an
// integer representation of a cell instead of using a QPoint.
const QPoint cell = q_func()->cellAtIndex(modelIndex);
if (!cellIsValid(cell))
return -1;
- return modelIndexAtCell(cell);
+ return modelIndexAtCell(visualIndex ? cell : QPoint(modelIndex.column(), modelIndex.row()));
}
int QQuickTableViewPrivate::edgeToArrayIndex(Qt::Edge edge) const
@@ -2647,7 +2727,9 @@ FxTableItem *QQuickTableViewPrivate::createFxTableItem(const QPoint &cell, QQmlI
Q_Q(QQuickTableView);
bool ownItem = false;
- int modelIndex = modelIndexAtCell(cell);
+
+ int modelIndex = modelIndexAtCell(isTransposed ? QPoint(logicalRowIndex(cell.x()), logicalColumnIndex(cell.y())) :
+ QPoint(logicalColumnIndex(cell.x()), logicalRowIndex(cell.y())));
QObject* object = model->object(modelIndex, incubationMode);
if (!object) {
@@ -3000,7 +3082,7 @@ qreal QQuickTableViewPrivate::getColumnWidth(int column) const
const int noExplicitColumnWidth = -1;
- if (cachedColumnWidth.startIndex == column)
+ if (cachedColumnWidth.startIndex == logicalColumnIndex(column))
return cachedColumnWidth.size;
if (syncHorizontally)
@@ -3019,7 +3101,7 @@ qreal QQuickTableViewPrivate::getColumnWidth(int column) const
qreal columnWidth = noExplicitColumnWidth;
if (columnWidthProvider.isCallable()) {
- auto const columnAsArgument = QJSValueList() << QJSValue(column);
+ auto const columnAsArgument = QJSValueList() << QJSValue(logicalColumnIndex(column));
columnWidth = columnWidthProvider.call(columnAsArgument).toNumber();
if (qIsNaN(columnWidth) || columnWidth < 0)
columnWidth = noExplicitColumnWidth;
@@ -3031,7 +3113,7 @@ qreal QQuickTableViewPrivate::getColumnWidth(int column) const
columnWidth = noExplicitColumnWidth;
}
- cachedColumnWidth.startIndex = column;
+ cachedColumnWidth.startIndex = logicalColumnIndex(column);
cachedColumnWidth.size = columnWidth;
return columnWidth;
}
@@ -3046,7 +3128,7 @@ qreal QQuickTableViewPrivate::getRowHeight(int row) const
const int noExplicitRowHeight = -1;
- if (cachedRowHeight.startIndex == row)
+ if (cachedRowHeight.startIndex == logicalRowIndex(row))
return cachedRowHeight.size;
if (syncVertically)
@@ -3065,7 +3147,7 @@ qreal QQuickTableViewPrivate::getRowHeight(int row) const
qreal rowHeight = noExplicitRowHeight;
if (rowHeightProvider.isCallable()) {
- auto const rowAsArgument = QJSValueList() << QJSValue(row);
+ auto const rowAsArgument = QJSValueList() << QJSValue(logicalRowIndex(row));
rowHeight = rowHeightProvider.call(rowAsArgument).toNumber();
if (qIsNaN(rowHeight) || rowHeight < 0)
rowHeight = noExplicitRowHeight;
@@ -3077,7 +3159,7 @@ qreal QQuickTableViewPrivate::getRowHeight(int row) const
rowHeight = noExplicitRowHeight;
}
- cachedRowHeight.startIndex = row;
+ cachedRowHeight.startIndex = logicalRowIndex(row);
cachedRowHeight.size = rowHeight;
return rowHeight;
}
@@ -4288,11 +4370,13 @@ void QQuickTableViewPrivate::initItemCallback(int modelIndex, QObject *object)
item->setZ(1);
const QPoint cell = cellAtModelIndex(modelIndex);
- const bool current = currentInSelectionModel(cell);
- const bool selected = selectedInSelectionModel(cell);
+ const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
+ const bool current = currentInSelectionModel(visualCell);
+ const bool selected = selectedInSelectionModel(visualCell);
setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), modelIndex, object, true);
setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), modelIndex, object, true);
setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(false), modelIndex, item, true);
+ setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(false), modelIndex, item, true);
if (auto attached = getAttachedObject(object))
attached->setView(q);
@@ -4309,11 +4393,13 @@ void QQuickTableViewPrivate::itemPooledCallback(int modelIndex, QObject *object)
void QQuickTableViewPrivate::itemReusedCallback(int modelIndex, QObject *object)
{
const QPoint cell = cellAtModelIndex(modelIndex);
- const bool current = currentInSelectionModel(cell);
- const bool selected = selectedInSelectionModel(cell);
+ const QPoint visualCell = QPoint(visualColumnIndex(cell.x()), visualRowIndex(cell.y()));
+ const bool current = currentInSelectionModel(visualCell);
+ const bool selected = selectedInSelectionModel(visualCell);
setRequiredProperty(kRequiredProperty_current, QVariant::fromValue(current), modelIndex, object, false);
setRequiredProperty(kRequiredProperty_selected, QVariant::fromValue(selected), modelIndex, object, false);
// Note: the edit item will never be reused, so no reason to set kRequiredProperty_editing
+ setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(false), modelIndex, object, false);
if (auto item = qobject_cast<QQuickItem*>(object))
QQuickItemPrivate::get(item)->setCulled(false);
@@ -4896,6 +4982,7 @@ void QQuickTableViewPrivate::init()
hoverHandler = new QQuickTableViewHoverHandler(q);
resizeHandler = new QQuickTableViewResizeHandler(q);
+
hoverHandler->setEnabled(resizableRows || resizableColumns);
resizeHandler->setEnabled(resizableRows || resizableColumns);
@@ -5668,6 +5755,10 @@ void QQuickTableView::setSyncView(QQuickTableView *view)
if (d->assignedSyncView == view)
return;
+ // Clear existing index mapping information maintained
+ // in the current view
+ d->clearIndexMapping();
+
d->assignedSyncView = view;
d->scheduleRebuildTable(QQuickTableViewPrivate::RebuildOption::ViewportOnly);
@@ -6012,6 +6103,169 @@ void QQuickTableView::positionViewAtCell(int column, int row, PositionMode mode,
}
#endif
+void QQuickTableView::moveColumn(int source, int destination)
+{
+ Q_D(QQuickTableView);
+ d->moveSection(source, destination, Qt::Horizontal);
+}
+
+void QQuickTableView::moveRow(int source, int destination)
+{
+ Q_D(QQuickTableView);
+ d->moveSection(source, destination, Qt::Vertical);
+}
+
+void QQuickTableViewPrivate::moveSection(int source, int destination, Qt::Orientations orientation)
+{
+ Q_Q(QQuickTableView);
+
+ if (source < 0 || destination < 0 ||
+ (orientation == Qt::Horizontal &&
+ (source >= tableSize.width() || destination >= tableSize.width())) ||
+ (orientation == Qt::Vertical &&
+ (source >= tableSize.height() || destination >= tableSize.height())))
+ return;
+
+ if (source == destination)
+ return;
+
+ if (m_sectionState != SectionState::Moving) {
+ m_sectionState = SectionState::Moving;
+ if (syncView)
+ syncView->d_func()->moveSection(source, destination, orientation);
+ else {
+ // Initialize the visual and logical index mapping
+ initializeIndexMapping();
+
+ // Set current index mapping according to moving rows or columns
+ SectionData *visualIndex = nullptr;
+ SectionData *logicalIndex = nullptr;
+
+ if (orientation == Qt::Horizontal) {
+ visualIndex = visualIndices[0].data();
+ logicalIndex = logicalIndices[0].data();
+ } else if (orientation == Qt::Vertical) {
+ visualIndex = visualIndices[1].data();
+ logicalIndex = logicalIndices[1].data();
+ }
+
+ const int logical = logicalIndex[source].index;
+ int visual = source;
+
+ if (destination > source) {
+ while (visual < destination) {
+ SectionData &visualData = visualIndex[logicalIndex[visual + 1].index];
+ SectionData &logicalData = logicalIndex[visual];
+ visualData.prevIndex = visualData.index;
+ visualData.index = visual;
+ logicalData.prevIndex = logicalData.index;
+ logicalData.index = logicalIndex[visual + 1].index;
+ ++visual;
+ }
+ } else {
+ while (visual > destination) {
+ SectionData &visualData = visualIndex[logicalIndex[visual - 1].index];
+ SectionData &logicalData = logicalIndex[visual];
+ visualData.prevIndex = visualData.index;
+ visualData.index = visual;
+ logicalData.prevIndex = logicalData.index;
+ logicalData.index = logicalIndex[visual - 1].index;
+ --visual;
+ }
+ }
+
+ visualIndex[logical].prevIndex = visualIndex[logical].index;
+ visualIndex[logical].index = destination;
+ logicalIndex[destination].prevIndex = logicalIndex[destination].index;
+ logicalIndex[destination].index = logical;
+
+ // Trigger section move for horizontal and vertical child views
+ // Used in a case where moveSection() triggered for table view
+ for (auto syncChild : std::as_const(syncChildren)) {
+ auto syncChild_d = syncChild->d_func();
+ if (syncChild_d->m_sectionState != SectionState::Moving &&
+ ((syncChild_d->syncHorizontally && orientation == Qt::Horizontal) ||
+ (syncChild_d->syncVertically && orientation == Qt::Vertical)))
+ syncChild_d->moveSection(source, destination, orientation);
+ }
+ }
+
+ // Rebuild the view to reflect the section order
+ scheduleRebuildTable(RebuildOption::ViewportOnly);
+ m_sectionState = SectionState::Idle;
+
+ // Emit section moved signal for the sections moved in the view
+ const int startIndex = (source > destination) ? destination : source;
+ const int endIndex = (source > destination) ? source : destination;
+ const int mapIndex = static_cast<int>(orientation) - 1;
+ for (int index = startIndex; index <= endIndex; index++) {
+ const SectionData *logicalDataIndices = (syncView ? syncView->d_func()->logicalIndices[mapIndex].constData() : logicalIndices[mapIndex].constData());
+ const SectionData *visualDataIndices = syncView ? syncView->d_func()->visualIndices[mapIndex].constData() : visualIndices[mapIndex].constData();
+ const int prevLogicalIndex = logicalDataIndices[index].prevIndex;
+ if (orientation == Qt::Horizontal)
+ emit q->columnMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
+ else
+ emit q->rowMoved(prevLogicalIndex, visualDataIndices[prevLogicalIndex].prevIndex, visualDataIndices[prevLogicalIndex].index);
+ }
+ }
+}
+
+void QQuickTableView::clearColumnReordering()
+{
+ Q_D(QQuickTableView);
+ d->clearSection(Qt::Horizontal);
+}
+
+void QQuickTableView::clearRowReordering()
+{
+ Q_D(QQuickTableView);
+ d->clearSection(Qt::Vertical);
+}
+
+void QQuickTableViewPrivate::clearSection(Qt::Orientations orientation)
+{
+ Q_Q(QQuickTableView);
+
+ const int mapIndex = static_cast<int>(orientation) - 1;
+ const QList<SectionData> oldLogicalIndices = syncView ? syncView->d_func()->logicalIndices[mapIndex] : logicalIndices[mapIndex];
+ const QList<SectionData> oldVisualIndices = syncView ? syncView->d_func()->visualIndices[mapIndex] : visualIndices[mapIndex];;
+
+ if (syncView)
+ syncView->d_func()->clearSection(orientation);
+ else {
+ // Clear the index mapping and rebuild the table
+ logicalIndices[mapIndex].clear();
+ visualIndices[mapIndex].clear();
+ scheduleRebuildTable(RebuildOption::ViewportOnly);
+ }
+
+ // Emit section moved signal for the sections moved in the view
+ for (int index = 0; index < oldLogicalIndices.size(); index++) {
+ const SectionData *logicalDataIndices = oldLogicalIndices.constData();
+ const SectionData *visualDataIndices = oldVisualIndices.constData();
+ if (logicalDataIndices[index].index != index) {
+ const int currentIndex = logicalDataIndices[index].index;
+ if (orientation == Qt::Horizontal)
+ emit q->columnMoved(currentIndex, visualDataIndices[currentIndex].index, index);
+ else
+ emit q->rowMoved(currentIndex, visualDataIndices[currentIndex].index, index);
+ }
+ }
+}
+
+void QQuickTableViewPrivate::setContainsDragOnDelegateItem(const QModelIndex &modelIndex, bool overlay)
+{
+ if (!modelIndex.isValid())
+ return;
+
+ const int cellIndex = modelIndexToCellIndex(modelIndex);
+ if (!loadedItems.contains(cellIndex))
+ return;
+ const QPoint cell = cellAtModelIndex(cellIndex);
+ QQuickItem *item = loadedTableItem(cell)->item;
+ setRequiredProperty(kRequiredProperty_containsDrag, QVariant::fromValue(overlay), cellIndex, item, false);
+}
+
QQuickItem *QQuickTableView::itemAtCell(const QPoint &cell) const
{
Q_D(const QQuickTableView);
@@ -6190,9 +6444,9 @@ void QQuickTableView::setColumnWidth(int column, qreal size)
return;
if (size < 0)
- d->explicitColumnWidths.remove(column);
+ d->explicitColumnWidths.remove(d->logicalColumnIndex(column));
else
- d->explicitColumnWidths.insert(column, size);
+ d->explicitColumnWidths.insert(d->logicalColumnIndex(column), size);
if (d->loadedItems.isEmpty())
return;
@@ -6225,7 +6479,7 @@ qreal QQuickTableView::explicitColumnWidth(int column) const
if (d->syncHorizontally)
return d->syncView->explicitColumnWidth(column);
- const auto it = d->explicitColumnWidths.constFind(column);
+ const auto it = d->explicitColumnWidths.constFind(d->logicalColumnIndex(column));
if (it != d->explicitColumnWidths.constEnd())
return *it;
return -1;
@@ -6248,9 +6502,9 @@ void QQuickTableView::setRowHeight(int row, qreal size)
return;
if (size < 0)
- d->explicitRowHeights.remove(row);
+ d->explicitRowHeights.remove(d->logicalRowIndex(row));
else
- d->explicitRowHeights.insert(row, size);
+ d->explicitRowHeights.insert(d->logicalRowIndex(row), size);
if (d->loadedItems.isEmpty())
return;
@@ -6283,7 +6537,7 @@ qreal QQuickTableView::explicitRowHeight(int row) const
if (d->syncVertically)
return d->syncView->explicitRowHeight(row);
- const auto it = d->explicitRowHeights.constFind(row);
+ const auto it = d->explicitRowHeights.constFind(d->logicalRowIndex(row));
if (it != d->explicitRowHeights.constEnd())
return *it;
return -1;
@@ -6299,14 +6553,15 @@ QModelIndex QQuickTableView::modelIndex(const QPoint &cell) const
if (!qaim)
return {};
- return qaim->index(cell.y(), cell.x());
+ return qaim->index(d->logicalRowIndex(cell.y()), d->logicalColumnIndex(cell.x()));
}
QPoint QQuickTableView::cellAtIndex(const QModelIndex &index) const
{
if (!index.isValid() || index.parent().isValid())
return {-1, -1};
- return {index.column(), index.row()};
+ Q_D(const QQuickTableView);
+ return {d->visualColumnIndex(index.column()), d->visualRowIndex(index.row())};
}
#if QT_DEPRECATED_SINCE(6, 4)
@@ -6371,7 +6626,8 @@ void QQuickTableView::edit(const QModelIndex &index)
// is currently dependent of the QQmlTableInstanceModel that was used to create the object
// in order to initialize required properties, so we need to set the editItem variable
// early on, so that we can use it in setRequiredProperty.
- d->editIndex = modelIndex(d->cellAtModelIndex(serializedModelIndex));
+ const QPoint cell = d->cellAtModelIndex(serializedModelIndex);
+ d->editIndex = modelIndex({d->visualColumnIndex(cell.x()), d->visualRowIndex(cell.y())});
d->editItem = qmlobject_cast<QQuickItem*>(object);
if (!d->editItem)
return;
@@ -6400,7 +6656,7 @@ void QQuickTableView::edit(const QModelIndex &index)
d->editModel->setModel(d->tableModel->model());
d->editModel->setDelegate(attached->editDelegate());
- const int cellIndex = d->modelIndexToCellIndex(index);
+ const int cellIndex = d->modelIndexToCellIndex(index, false);
QObject* object = d->editModel->object(cellIndex, QQmlIncubator::Synchronous);
if (!object) {
d->editIndex = QModelIndex();
@@ -6451,7 +6707,7 @@ void QQuickTableView::closeEditor()
d->editItem = nullptr;
cellItem->setZ(1);
- const int cellIndex = d->modelIndexToCellIndex(d->editIndex);
+ const int cellIndex = d->modelIndexToCellIndex(d->editIndex, false);
d->setRequiredProperty(kRequiredProperty_editing, QVariant::fromValue(false), cellIndex, cellItem, false);
// Remove the extra reference we sat on the cell item from edit()
d->model->release(cellItem, QQmlInstanceModel::NotReusable);
@@ -6669,7 +6925,6 @@ void QQuickTableView::setResizableRows(bool enabled)
}
// ----------------------------------------------
-
QQuickTableViewHoverHandler::QQuickTableViewHoverHandler(QQuickTableView *view)
: QQuickHoverHandler(view->contentItem())
{
@@ -6720,13 +6975,35 @@ void QQuickTableViewHoverHandler::handleEventPoint(QPointerEvent *event, QEventP
// ----------------------------------------------
-QQuickTableViewResizeHandler::QQuickTableViewResizeHandler(QQuickTableView *view)
+QQuickTableViewPointerHandler::QQuickTableViewPointerHandler(QQuickTableView *view)
: QQuickSinglePointHandler(view->contentItem())
{
- setMargin(5);
// Set a grab permission that stops the flickable, as well as
// any drag handler inside the delegate, from stealing the drag.
setGrabPermissions(QQuickPointerHandler::CanTakeOverFromAnything);
+}
+
+bool QQuickTableViewPointerHandler::wantsEventPoint(const QPointerEvent *event, const QEventPoint &point)
+{
+ if (!QQuickSinglePointHandler::wantsEventPoint(event, point))
+ return false;
+
+ // If we have a mouse wheel event then we do not want to do anything related to resizing.
+ if (event->type() == QEvent::Type::Wheel)
+ return false;
+
+ // When the user is flicking, we disable resizing, so that
+ // he doesn't start to resize by accident.
+ const auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ return !tableView->isMoving();
+}
+
+// ----------------------------------------------
+
+QQuickTableViewResizeHandler::QQuickTableViewResizeHandler(QQuickTableView *view)
+ : QQuickTableViewPointerHandler(view)
+{
+ setMargin(5);
setObjectName("tableViewResizeHandler");
}
@@ -6754,23 +7031,14 @@ void QQuickTableViewResizeHandler::onGrabChanged(QQuickPointerHandler *grabber
}
}
-bool QQuickTableViewResizeHandler::wantsEventPoint(const QPointerEvent *event, const QEventPoint &point)
-{
- if (!QQuickSinglePointHandler::wantsEventPoint(event, point))
- return false;
-
- // If we have a mouse wheel event then we do not want to do anything related to resizing.
- if (event->type() == QEvent::Type::Wheel)
- return false;
-
- // When the user is flicking, we disable resizing, so that
- // he doesn't start to resize by accident.
- auto tableView = static_cast<QQuickTableView *>(parentItem()->parent());
- return !tableView->isMoving();
-}
-
void QQuickTableViewResizeHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
{
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
+ const auto *activeHandler = tableViewPrivate->activePointerHandler();
+ if (activeHandler && !qobject_cast<const QQuickTableViewResizeHandler *>(activeHandler))
+ return;
+
// Resolve which state we're in first...
updateState(point);
// ...and act on it next
@@ -6835,6 +7103,7 @@ void QQuickTableViewResizeHandler::updateDrag(QPointerEvent *event, QEventPoint
// pointer handlers to do flicking, so setting an exclusive grab (together
// with grab permissions) doens't work ATM.
tableView->setFiltersChildMouseEvents(false);
+ tableViewPrivate->setActivePointerHandler(this);
break;
case DraggingStarted:
setExclusiveGrab(event, point, true);
@@ -6856,6 +7125,7 @@ void QQuickTableViewResizeHandler::updateDrag(QPointerEvent *event, QEventPoint
break; }
case DraggingFinished: {
tableView->setFiltersChildMouseEvents(true);
+ tableViewPrivate->setActivePointerHandler(nullptr);
#if QT_CONFIG(cursor)
tableViewPrivate->updateCursor();
#endif
@@ -6864,6 +7134,316 @@ void QQuickTableViewResizeHandler::updateDrag(QPointerEvent *event, QEventPoint
}
// ----------------------------------------------
+QQuickTableViewSectionDragHandler::QQuickTableViewSectionDragHandler(QQuickTableView *view)
+ : QQuickTableViewPointerHandler(view)
+{
+ setObjectName("tableViewDragHandler");
+}
+
+QQuickTableViewSectionDragHandler::~QQuickTableViewSectionDragHandler()
+{
+ resetDragData();
+}
+
+void QQuickTableViewSectionDragHandler::resetDragData()
+{
+ if (m_state != Listening) {
+ m_state = Listening;
+ resetSectionOverlay();
+ m_source = -1;
+ m_destination = -1;
+ if (m_grabResult.data())
+ m_grabResult.data()->disconnect();
+ if (!m_drag.isNull()) {
+ m_drag->disconnect();
+ delete m_drag;
+ }
+ if (!m_dropArea.isNull()) {
+ m_dropArea->disconnect();
+ delete m_dropArea;
+ }
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ tableView->setFiltersChildMouseEvents(true);
+ }
+}
+
+void QQuickTableViewSectionDragHandler::resetSectionOverlay()
+{
+ if (m_destination != -1) {
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
+ const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : m_destination;
+ const int column = (m_sectionOrientation == Qt::Horizontal) ? m_destination : 0;
+ tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column), false);
+ m_destination = -1;
+ }
+}
+
+void QQuickTableViewSectionDragHandler::grabSection()
+{
+ // Generate the transparent section image in pixmap
+ QPixmap pixmap(m_grabResult->image().size());
+ pixmap.fill(Qt::transparent);
+ QPainter painter(&pixmap);
+ painter.setOpacity(0.6);
+ painter.drawImage(0, 0, m_grabResult->image());
+ painter.end();
+
+ // Specify the pixmap and mime data to be as drag object
+ auto *mimeData = new QMimeData();
+ mimeData->setImageData(pixmap);
+ m_drag->setMimeData(mimeData);
+ m_drag->setPixmap(pixmap);
+}
+
+void QQuickTableViewSectionDragHandler::handleDrop(QQuickDragEvent *event)
+{
+ Q_UNUSED(event);
+
+ if (m_state == Dragging) {
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
+ tableViewPrivate->moveSection(m_source, m_destination, m_sectionOrientation);
+ m_state = DraggingFinished;
+ resetSectionOverlay();
+ if (m_scrollTimer.isActive())
+ m_scrollTimer.stop();
+ }
+}
+
+void QQuickTableViewSectionDragHandler::handleDrag(QQuickDragEvent *event)
+{
+ Q_UNUSED(event);
+
+ if (m_state == Dragging) {
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ const QPoint dragItemPosition(tableView->contentX() + event->x(), tableView->contentY() + event->y());
+ const auto *sourceItem = qobject_cast<QQuickItem *>(m_drag->source());
+ const QPoint targetCell = tableView->cellAtPosition(dragItemPosition, true);
+
+ auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
+ const int newDestination = (m_sectionOrientation == Qt::Horizontal) ? targetCell.x() : targetCell.y();
+ if (newDestination != m_destination) {
+ // Reset the overlay property in the existing model delegate item
+ resetSectionOverlay();
+ // Set the overlay property in the new model delegate item
+ const int row = (m_sectionOrientation == Qt::Horizontal) ? 0 : newDestination;
+ const int column = (m_sectionOrientation == Qt::Horizontal) ? newDestination : 0;
+ tableViewPrivate->setContainsDragOnDelegateItem(tableView->index(row, column), true);
+ m_destination = newDestination;
+ }
+
+ // Scroll header view while section item moves out of the table boundary
+ const QPoint dragItemStartPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() - sourceItem->width() / 2, dragItemPosition.y()) :
+ QPoint(dragItemPosition.x(), dragItemPosition.y() - sourceItem->height() / 2);
+ const QPoint dragItemEndPos = (m_sectionOrientation == Qt::Horizontal) ? QPoint(dragItemPosition.x() + sourceItem->width() / 2, dragItemPosition.y()) :
+ QPoint(dragItemPosition.x(), dragItemPosition.y() + sourceItem->height() / 2);
+ const bool useStartPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemStartPos.x() <= tableView->contentX()) : (dragItemStartPos.y() <= tableView->contentY());
+ const bool useEndPos = (m_sectionOrientation == Qt::Horizontal) ? (dragItemEndPos.x() >= tableView->width()) : (dragItemEndPos.y() >= tableView->height());
+ if (useStartPos || useEndPos) {
+ if (!m_scrollTimer.isActive()) {
+ m_dragPoint = (m_sectionOrientation == Qt::Horizontal) ? QPoint(useStartPos ? dragItemStartPos.x() : dragItemEndPos.x(), 0) :
+ QPoint(0, useStartPos ? dragItemStartPos.y() : dragItemEndPos.y());
+ m_scrollTimer.start(1);
+ }
+ } else {
+ if (m_scrollTimer.isActive())
+ m_scrollTimer.stop();
+ }
+ }
+}
+
+void QQuickTableViewSectionDragHandler::handleDragDropAction(Qt::DropAction action)
+{
+ // Reset the overlay property in the model delegate item when drag or drop
+ // happens outside specified drop area (i.e. during ignore action)
+ if (action == Qt::IgnoreAction) {
+ resetSectionOverlay();
+ if (m_scrollTimer.isActive())
+ m_scrollTimer.stop();
+ }
+}
+
+void QQuickTableViewSectionDragHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point)
+{
+ QQuickSinglePointHandler::handleEventPoint(event, point);
+
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ auto *tableViewPrivate = QQuickTableViewPrivate::get(tableView);
+ const auto *activeHandler = tableViewPrivate->activePointerHandler();
+ if (activeHandler && !qobject_cast<const QQuickTableViewSectionDragHandler *>(activeHandler))
+ return;
+
+ if (m_state == DraggingFinished) {
+ if (m_scrollTimer.isActive())
+ m_scrollTimer.stop();
+ resetDragData();
+ }
+
+ if (point.state() == QEventPoint::Pressed) {
+ // Reset the information in the drag handler
+ resetDragData();
+ // Activate the passive grab to get further move updates
+ setPassiveGrab(event, point, true);
+ // Disable flicking while dragging. TableView uses filtering instead of
+ // pointer handlers to do flicking, so setting an exclusive grab (together
+ // with grab permissions) doens't work ATM.
+ auto *tableView = static_cast<QQuickTableView *>(parentItem()->parent());
+ tableView->setFiltersChildMouseEvents(false);
+ m_state = Tracking;
+ } else if (point.state() == QEventPoint::Released) {
+ // Reset the information in the drag handler
+ if (m_scrollTimer.isActive())
+ m_scrollTimer.stop();
+ resetDragData();
+ } else if (point.state() == QEventPoint::Updated) {
+ // Check to see that the movement can be considered as dragging
+ const qreal distX = point.position().x() - point.pressPosition().x();
+ const qreal distY = point.position().y() - point.pressPosition().y();
+ const qreal dragDist = qSqrt(distX * distX + distY * distY);
+ if (dragDist > qApp->styleHints()->startDragDistance()) {
+ switch (m_state) {
+ case Tracking: {
+ // Grab the image for dragging header
+ const QPoint cell = tableView->cellAtPosition(point.position(), true);
+ auto *item = tableView->itemAtCell(cell);
+ if (m_drag.isNull()) {
+ m_drag = new QDrag(item);
+ connect(m_drag.data(), &QDrag::actionChanged, this,
+ &QQuickTableViewSectionDragHandler::handleDragDropAction);
+ }
+ // Connect the timer for scroling
+ QObject::connect(&m_scrollTimer, &QTimer::timeout, [&]{
+ const QSizeF dist = tableViewPrivate->scrollTowardsPoint(m_dragPoint, m_step);
+ m_dragPoint.rx() += dist.width() > 0 ? m_step.width() : -m_step.width();
+ m_dragPoint.ry() += dist.height() > 0 ? m_step.height() : -m_step.height();
+ m_step = QSizeF(qAbs(dist.width() * 0.010), qAbs(dist.height() * 0.010));
+ });
+ // Set the drop area
+ if (m_dropArea.isNull()) {
+ m_dropArea = new QQuickDropArea(tableView);
+ m_dropArea->setSize(tableView->size());
+ connect(m_dropArea, &QQuickDropArea::positionChanged, this,
+ &QQuickTableViewSectionDragHandler::handleDrag);
+ connect(m_dropArea, &QQuickDropArea::dropped, this,
+ &QQuickTableViewSectionDragHandler::handleDrop);
+ }
+ // Grab the image of the section
+ m_grabResult = item->grabToImage();
+ connect(m_grabResult.data(), &QQuickItemGrabResult::ready, this,
+ &QQuickTableViewSectionDragHandler::grabSection);
+ // Update source depending on the type of orientation
+ m_source = (m_sectionOrientation == Qt::Horizontal) ? cell.x() : cell.y();
+ m_state = DraggingStarted;
+ // Set drag handler as active and it further handles section pointer events
+ tableViewPrivate->setActivePointerHandler(this);
+ }
+ break;
+
+ case DraggingStarted: {
+ if (m_drag && m_drag->mimeData()) {
+ if (auto *item = qobject_cast<QQuickItem *>(m_drag->source())) {
+ m_state = Dragging;
+ const QPointF itemPos = item->mapFromItem(tableView->contentItem(), point.position());
+ Q_UNUSED(itemPos);
+ m_drag->setHotSpot(m_sectionOrientation == Qt::Horizontal ? QPoint(item->width()/2, itemPos.y()) : QPoint(itemPos.x(), item->height()/2));
+ m_drag->exec();
+ // Reset the active handler
+ tableViewPrivate->setActivePointerHandler(nullptr);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+// ----------------------------------------------
+void QQuickTableViewPrivate::initSectionDragHandler(Qt::Orientation orientation)
+{
+ if (!sectionDragHandler) {
+ Q_Q(QQuickTableView);
+ sectionDragHandler = new QQuickTableViewSectionDragHandler(q);
+ sectionDragHandler->setSectionOrientation(orientation);
+ }
+}
+
+void QQuickTableViewPrivate::destroySectionDragHandler()
+{
+ if (sectionDragHandler)
+ delete sectionDragHandler;
+}
+
+void QQuickTableViewPrivate::initializeIndexMapping()
+{
+ auto initIndices = [](auto& visualIndex, auto& logicalIndex, int size) {
+ visualIndex.resize(size);
+ logicalIndex.resize(size);
+ for (int index = 0; index < size; ++index)
+ visualIndex[index].index = logicalIndex[index].index = index;
+ };
+
+ if (!tableSize.isEmpty()) {
+ if (visualIndices[0].size() != tableSize.width()
+ || logicalIndices[0].size() != tableSize.width())
+ initIndices(visualIndices[0], logicalIndices[0], tableSize.width());
+
+ if (visualIndices[1].size() != tableSize.height()
+ || logicalIndices[1].size() != tableSize.height())
+ initIndices(visualIndices[1], logicalIndices[1], tableSize.height());
+ }
+}
+
+void QQuickTableViewPrivate::clearIndexMapping()
+{
+ logicalIndices[0].clear();
+ visualIndices[0].clear();
+
+ logicalIndices[1].clear();
+ visualIndices[1].clear();
+}
+
+int QQuickTableViewPrivate::logicalRowIndex(const int visualIndex) const
+{
+ if (syncView)
+ return syncView->d_func()->logicalRowIndex(visualIndex);
+ if (logicalIndices[1].isEmpty() || visualIndex < 0)
+ return visualIndex;
+ return logicalIndices[1].constData()[visualIndex].index;
+}
+
+int QQuickTableViewPrivate::logicalColumnIndex(const int visualIndex) const
+{
+ if (syncView)
+ return syncView->d_func()->logicalColumnIndex(visualIndex);
+ if (logicalIndices[0].isEmpty() || visualIndex < 0)
+ return visualIndex;
+ return logicalIndices[0].constData()[visualIndex].index;
+}
+
+int QQuickTableViewPrivate::visualRowIndex(const int logicalIndex) const
+{
+ if (syncView)
+ return syncView->d_func()->visualRowIndex(logicalIndex);
+ if (visualIndices[1].isEmpty() || logicalIndex < 0)
+ return logicalIndex;
+ return visualIndices[1].constData()[logicalIndex].index;
+}
+
+int QQuickTableViewPrivate::visualColumnIndex(const int logicalIndex) const
+{
+ if (syncView)
+ return syncView->d_func()->visualColumnIndex(logicalIndex);
+ if (visualIndices[0].isEmpty() || logicalIndex < 0)
+ return logicalIndex;
+ return visualIndices[0].constData()[logicalIndex].index;
+}
+
+// ----------------------------------------------
QQuickTableViewTapHandler::QQuickTableViewTapHandler(QQuickTableView *view)
: QQuickTapHandler(view->contentItem())
diff --git a/src/quick/items/qquicktableview_p.h b/src/quick/items/qquicktableview_p.h
index cdde6de3d6..10cc53274d 100644
--- a/src/quick/items/qquicktableview_p.h
+++ b/src/quick/items/qquicktableview_p.h
@@ -233,6 +233,11 @@ public:
Q_INVOKABLE void positionViewAtCell(int column, int row, PositionMode mode, const QPointF &offset = QPointF(), const QRectF &subRect = QRectF());
#endif
+ Q_REVISION(6, 8) Q_INVOKABLE void moveColumn(int source, int destination);
+ Q_REVISION(6, 8) Q_INVOKABLE void moveRow(int source, int destination);
+ Q_REVISION(6, 8) Q_INVOKABLE void clearColumnReordering();
+ Q_REVISION(6, 8) Q_INVOKABLE void clearRowReordering();
+
static QQuickTableViewAttached *qmlAttachedProperties(QObject *);
Q_SIGNALS:
@@ -264,6 +269,9 @@ Q_SIGNALS:
Q_REVISION(6, 5) void editTriggersChanged();
Q_REVISION(6, 5) void layoutChanged();
Q_REVISION(6, 6) void selectionModeChanged();
+ Q_REVISION(6, 8) void rowMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
+ Q_REVISION(6, 8) void columnMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
+
protected:
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index 867e03485a..ea49a3309b 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -23,8 +23,8 @@
#include <QtQml/private/qqmlincubator_p.h>
#include <QtQmlModels/private/qqmlchangeset_p.h>
#include <QtQml/qqmlinfo.h>
+#include <QtGui/qdrag.h>
-#include <QtQuick/private/qminimalflatset_p.h>
#include <QtQuick/private/qquickflickable_p_p.h>
#include <QtQuick/private/qquickitemviewfxitem_p_p.h>
#include <QtQuick/private/qquickanimation_p.h>
@@ -32,6 +32,9 @@
#include <QtQuick/private/qquicksinglepointhandler_p.h>
#include <QtQuick/private/qquickhoverhandler_p.h>
#include <QtQuick/private/qquicktaphandler_p.h>
+#include <QtQuick/private/qquickdroparea_p.h>
+
+#include <QtCore/private/qminimalflatset_p.h>
QT_BEGIN_NAMESPACE
@@ -67,15 +70,10 @@ protected:
void handleEventPoint(QPointerEvent *event, QEventPoint &point) override;
};
-/*! \internal
- * TableView uses QQuickTableViewResizeHandler to enable the user to resize
- * rows and columns. By using a custom pointer handler, we can get away with
- * using a single pointer handler for the whole content item, rather than
- * e.g having to split it up into multiple items with drag handlers placed
- * between the cells.
- */
-class QQuickTableViewResizeHandler : public QQuickSinglePointHandler
+class QQuickTableViewPointerHandler : public QQuickSinglePointHandler
{
+ Q_OBJECT
+
public:
enum State {
Listening, // the pointer is not being pressed between the cells
@@ -85,12 +83,28 @@ public:
DraggingFinished // dragging was finished
};
- QQuickTableViewResizeHandler(QQuickTableView *view);
- State state() { return m_state; }
- void updateState(QEventPoint &point);
- void updateDrag(QPointerEvent *event, QEventPoint &point);
+ QQuickTableViewPointerHandler(QQuickTableView *view);
State m_state = Listening;
+ State state() { return m_state; }
+
+protected:
+ bool wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) override;
+};
+
+/*! \internal
+ * TableView uses QQuickTableViewResizeHandler to enable the user to resize
+ * rows and columns. By using a custom pointer handler, we can get away with
+ * using a single pointer handler for the whole content item, rather than
+ * e.g having to split it up into multiple items with drag handlers placed
+ * between the cells.
+ */
+class QQuickTableViewResizeHandler : public QQuickTableViewPointerHandler
+{
+ Q_OBJECT
+
+public:
+ QQuickTableViewResizeHandler(QQuickTableView *view);
int m_row = -1;
qreal m_rowStartY = -1;
@@ -100,15 +114,54 @@ public:
qreal m_columnStartX = -1;
qreal m_columnStartWidth = -1;
+ void updateState(QEventPoint &point);
+ void updateDrag(QPointerEvent *event, QEventPoint &point);
+
friend class QQuickTableViewPrivate;
protected:
- bool wantsEventPoint(const QPointerEvent *event, const QEventPoint &point) override;
void handleEventPoint(QPointerEvent *event, QEventPoint &point) override;
void onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition,
QPointerEvent *ev, QEventPoint &point) override;
};
+class QQuickTableViewSectionDragHandler : public QQuickTableViewPointerHandler
+{
+ Q_OBJECT
+
+public:
+ QQuickTableViewSectionDragHandler(QQuickTableView *view);
+ ~QQuickTableViewSectionDragHandler();
+
+ void grabSection();
+
+ void handleDrag(QQuickDragEvent *event);
+ void handleDrop(QQuickDragEvent *event);
+ void handleDragDropAction(Qt::DropAction action);
+
+ void setSectionOrientation(Qt::Orientation orientation) { m_sectionOrientation = orientation; }
+
+ friend class QQuickTableViewPrivate;
+
+protected:
+ void handleEventPoint(QPointerEvent *event, QEventPoint &point) override;
+
+private:
+ void resetDragData();
+ void resetSectionOverlay();
+
+ QSharedPointer<QQuickItemGrabResult> m_grabResult;
+ QPointer<QDrag> m_drag;
+ int m_source = -1;
+ int m_destination = -1;
+ QPointer<QQuickDropArea> m_dropArea;
+ Qt::Orientation m_sectionOrientation;
+
+ QPointF m_dragPoint;
+ QSizeF m_step = QSizeF(1, 1);
+ QTimer m_scrollTimer;
+};
+
/*! \internal
* QQuickTableViewTapHandler used to handle tap events explicitly for table view
*/
@@ -123,7 +176,6 @@ public:
friend class QQuickTableViewPrivate;
};
-
class Q_QUICK_EXPORT QQuickTableViewPrivate : public QQuickFlickablePrivate, public QQuickSelectable
{
public:
@@ -240,6 +292,11 @@ public:
Done
};
+ enum class SectionState {
+ Idle = 0,
+ Moving
+ };
+
enum class RebuildOption {
None = 0,
All = 0x1,
@@ -393,6 +450,8 @@ public:
QQuickTableViewHoverHandler *hoverHandler = nullptr;
QQuickTableViewResizeHandler *resizeHandler = nullptr;
+ QQuickTableViewSectionDragHandler *sectionDragHandler = nullptr;
+ QQuickTableViewPointerHandler *activePtrHandler = nullptr;
QQmlTableInstanceModel *editModel = nullptr;
QQuickItem *editItem = nullptr;
@@ -403,6 +462,16 @@ public:
QString forcedIncubationMode = qEnvironmentVariable("QT_TABLEVIEW_INCUBATION_MODE");
#endif
+ struct SectionData {
+ int index = -1;
+ int prevIndex = -1;
+ };
+
+ QList<SectionData> visualIndices[Qt::Vertical];
+ QList<SectionData> logicalIndices[Qt::Vertical];
+
+ SectionState m_sectionState = SectionState::Idle;
+
public:
void init();
@@ -410,7 +479,7 @@ public:
int modelIndexAtCell(const QPoint &cell) const;
QPoint cellAtModelIndex(int modelIndex) const;
- int modelIndexToCellIndex(const QModelIndex &modelIndex) const;
+ int modelIndexToCellIndex(const QModelIndex &modelIndex, bool visualIndex = true) const;
inline bool cellIsValid(const QPoint &cell) const { return cell.x() != -1 && cell.y() != -1; }
qreal sizeHintForColumn(int column) const;
@@ -589,7 +658,7 @@ public:
void clearSelection() override;
void normalizeSelection() override;
QRectF selectionRectangle() const override;
- QSizeF scrollTowardsSelectionPoint(const QPointF &pos, const QSizeF &step) override;
+ QSizeF scrollTowardsPoint(const QPointF &pos, const QSizeF &step) override;
void setCallback(std::function<void(CallBackFlag)> func) override;
void cancelSelectionTracking();
@@ -597,6 +666,22 @@ public:
virtual void updateSelection(const QRect &oldSelection, const QRect &newSelection);
QRect selection() const;
// ----------------
+
+ // Section drag handler
+ void initSectionDragHandler(Qt::Orientation orientation);
+ void destroySectionDragHandler();
+ inline void setActivePointerHandler(QQuickTableViewPointerHandler *handler) { activePtrHandler = handler; }
+ inline QQuickTableViewPointerHandler* activePointerHandler() const { return activePtrHandler; }
+ // Row/Column reordering
+ void moveSection(int source , int destination, Qt::Orientations orientation);
+ void initializeIndexMapping();
+ void clearIndexMapping();
+ void clearSection(Qt::Orientations orientation);
+ virtual int logicalRowIndex(const int visualIndex) const;
+ virtual int logicalColumnIndex(const int visualIndex) const;
+ virtual int visualRowIndex(const int logicalIndex) const;
+ virtual int visualColumnIndex(const int logicalIndex) const;
+ void setContainsDragOnDelegateItem(const QModelIndex &modelIndex, bool overlay);
};
class FxTableItem : public QQuickItemViewFxItem
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index af3fe3d1d4..e29495f451 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -34,8 +34,7 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcHoverTrace)
-Q_LOGGING_CATEGORY(lcText, "qt.quick.text")
+Q_STATIC_LOGGING_CATEGORY(lcText, "qt.quick.text")
using namespace Qt::StringLiterals;
@@ -1850,7 +1849,7 @@ QQuickText::~QQuickText()
*/
/*!
- \qmlproperty object QtQuick::Text::font.contextFontMerging
+ \qmlproperty bool QtQuick::Text::font.contextFontMerging
\since 6.8
//! [qml-font-context-font-merging]
@@ -1868,6 +1867,32 @@ QQuickText::~QQuickText()
//! [qml-font-context-font-merging]
*/
+/*!
+ \qmlproperty bool QtQuick::Text::font.preferTypoLineMetrics
+ \since 6.8
+
+//! [qml-font-prefer-typo-line-metrics] For compatibility reasons, OpenType fonts contain two
+ competing sets of the vertical line metrics that provide the \l{QFontMetricsF::ascent()}{ascent},
+ \l{QFontMetricsF::descent()}{descent} and \l{QFontMetricsF::leading()}{leading} of the font. These
+ are often referred to as the
+ \l{https://learn.microsoft.com/en-us/typography/opentype/spec/os2#uswinascent}{win} (Windows)
+ metrics and the \l{https://learn.microsoft.com/en-us/typography/opentype/spec/os2#sta}{typo}
+ (typographical) metrics. While the specification recommends using the \c typo metrics for line
+ spacing, many applications prefer the \c win metrics unless the \c{USE_TYPO_METRICS} flag is set in
+ the \l{https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fsselection}{fsSelection}
+ field of the font. For backwards-compatibility reasons, this is also the case for Qt applications.
+ This is not an issue for fonts that set the \c{USE_TYPO_METRICS} flag to indicate that the \c{typo}
+ metrics are valid, nor for fonts where the \c{win} metrics and \c{typo} metrics match up. However,
+ for certain fonts the \c{win} metrics may be larger than the preferable line spacing and the
+ \c{USE_TYPO_METRICS} flag may be unset by mistake. For such fonts, setting
+ \c{font.preferTypoLineMetrics} may give superior results.
+
+ By default, \c preferTypoLineMetrics is \c{false}.
+
+ \sa QFont::StyleStrategy
+//! [qml-font-prefer-typo-line-metrics]
+*/
+
QFont QQuickText::font() const
{
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index 62b63f120d..cbc46f7728 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -42,7 +42,6 @@
const int textCursorWidth = 1;
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcHoverTrace)
// could go into QTextCursor...
static QTextLine currentTextLine(const QTextCursor &cursor)
@@ -584,25 +583,7 @@ void QQuickTextControl::clear()
QQuickTextControl::QQuickTextControl(QTextDocument *doc, QObject *parent)
: QInputControl(TextEdit, *new QQuickTextControlPrivate, parent)
{
- Q_D(QQuickTextControl);
- Q_ASSERT(doc);
-
- QAbstractTextDocumentLayout *layout = doc->documentLayout();
- qmlobject_connect(layout, QAbstractTextDocumentLayout, SIGNAL(update(QRectF)), this, QQuickTextControl, SIGNAL(updateRequest()));
- qmlobject_connect(layout, QAbstractTextDocumentLayout, SIGNAL(updateBlock(QTextBlock)), this, QQuickTextControl, SIGNAL(updateRequest()));
- qmlobject_connect(doc, QTextDocument, SIGNAL(contentsChanged()), this, QQuickTextControl, SIGNAL(textChanged()));
- qmlobject_connect(doc, QTextDocument, SIGNAL(contentsChanged()), this, QQuickTextControl, SLOT(_q_updateCurrentCharFormatAndSelection()));
- qmlobject_connect(doc, QTextDocument, SIGNAL(cursorPositionChanged(QTextCursor)), this, QQuickTextControl, SLOT(_q_updateCursorPosChanged(QTextCursor)));
- connect(doc, &QTextDocument::contentsChange, this, &QQuickTextControl::contentsChange);
-
- layout->setProperty("cursorWidth", textCursorWidth);
-
- d->doc = doc;
- d->cursor = QTextCursor(doc);
- d->lastCharFormat = d->cursor.charFormat();
- doc->setPageSize(QSizeF(0, 0));
- doc->setModified(false);
- doc->setUndoRedoEnabled(true);
+ setDocument(doc);
}
QQuickTextControl::~QQuickTextControl()
@@ -618,7 +599,29 @@ QTextDocument *QQuickTextControl::document() const
void QQuickTextControl::setDocument(QTextDocument *doc)
{
Q_D(QQuickTextControl);
+ if (!doc || d->doc == doc)
+ return;
+
d->doc = doc;
+ d->cursor = QTextCursor(doc);
+ d->lastCharFormat = d->cursor.charFormat();
+ doc->setPageSize(QSizeF(0, 0));
+ doc->setModified(false);
+ doc->setUndoRedoEnabled(true);
+
+ QAbstractTextDocumentLayout *layout = doc->documentLayout();
+ connect(layout, &QAbstractTextDocumentLayout::update, this, &QQuickTextControl::updateRequest);
+ connect(layout, &QAbstractTextDocumentLayout::updateBlock, this, &QQuickTextControl::updateRequest);
+ connect(doc, &QTextDocument::contentsChanged, doc, [d, this]() {
+ d->_q_updateCurrentCharFormatAndSelection();
+ emit textChanged();
+ });
+ connect(doc, &QTextDocument::cursorPositionChanged, doc, [d](const QTextCursor &cursor) {
+ d->_q_updateCursorPosChanged(cursor);
+ });
+ connect(doc, &QTextDocument::contentsChange, this, &QQuickTextControl::contentsChange);
+ if (auto *qtdlayout = qobject_cast<QTextDocumentLayout *>(layout))
+ qtdlayout->setCursorWidth(textCursorWidth);
}
void QQuickTextControl::updateCursorRectangle(bool force)
diff --git a/src/quick/items/qquicktextdocument.cpp b/src/quick/items/qquicktextdocument.cpp
index 7812cf107e..d5e7e77897 100644
--- a/src/quick/items/qquicktextdocument.cpp
+++ b/src/quick/items/qquicktextdocument.cpp
@@ -16,7 +16,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcTextDoc, "qt.quick.textdocument")
+Q_STATIC_LOGGING_CATEGORY(lcTextDoc, "qt.quick.textdocument")
using namespace Qt::StringLiterals;
@@ -589,10 +589,24 @@ QSizeF QQuickTextImageHandler::intrinsicSize(
{
if (format.isImageFormat()) {
QTextImageFormat imageFormat = format.toImageFormat();
- const int width = qRound(imageFormat.width());
+ int width = qRound(imageFormat.width());
const bool hasWidth = imageFormat.hasProperty(QTextFormat::ImageWidth) && width > 0;
const int height = qRound(imageFormat.height());
const bool hasHeight = imageFormat.hasProperty(QTextFormat::ImageHeight) && height > 0;
+ const auto maxWidth = imageFormat.maximumWidth();
+ const bool hasMaxWidth = imageFormat.hasProperty(QTextFormat::ImageMaxWidth) && maxWidth.type() != QTextLength::VariableLength;
+
+ int effectiveMaxWidth = INT_MAX;
+ if (hasMaxWidth) {
+ if (maxWidth.type() == QTextLength::PercentageLength) {
+ effectiveMaxWidth = (doc->pageSize().width() - 2 * doc->documentMargin()) * maxWidth.value(100) / 100;
+ } else {
+ effectiveMaxWidth = maxWidth.rawValue();
+ }
+
+ width = qMin(effectiveMaxWidth, width);
+ }
+
QSizeF size(width, height);
if (!hasWidth || !hasHeight) {
QVariant res = doc->resource(QTextDocument::ImageResource, QUrl(imageFormat.name()));
@@ -607,11 +621,17 @@ QSizeF QQuickTextImageHandler::intrinsicSize(
return size;
}
QSize imgSize = image.size();
+ if (imgSize.width() > effectiveMaxWidth) {
+ // image is bigger than effectiveMaxWidth, scale it down
+ imgSize.setHeight(effectiveMaxWidth * imgSize.height() / (qreal) imgSize.width());
+ imgSize.setWidth(effectiveMaxWidth);
+ }
+
if (!hasWidth) {
if (!hasHeight)
size.setWidth(imgSize.width());
else
- size.setWidth(qRound(height * (imgSize.width() / (qreal) imgSize.height())));
+ size.setWidth(qMin(effectiveMaxWidth, qRound(height * (imgSize.width() / (qreal) imgSize.height()))));
}
if (!hasHeight) {
if (!hasWidth)
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 02b34a6671..03e5c14ba1 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -34,8 +34,7 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcVP)
-Q_LOGGING_CATEGORY(lcTextEdit, "qt.quick.textedit")
+Q_STATIC_LOGGING_CATEGORY(lcTextEdit, "qt.quick.textedit")
using namespace Qt::StringLiterals;
@@ -376,13 +375,20 @@ QString QQuickTextEdit::text() const
*/
/*!
- \qmlproperty object QtQuick::TextEdit::font.contextFontMerging
+ \qmlproperty bool QtQuick::TextEdit::font.contextFontMerging
\since 6.8
\include qquicktext.cpp qml-font-context-font-merging
*/
/*!
+ \qmlproperty bool QtQuick::TextEdit::font.preferTypoLineMetrics
+ \since 6.8
+
+ \include qquicktext.cpp qml-font-prefer-typo-line-metrics
+*/
+
+/*!
\qmlproperty string QtQuick::TextEdit::text
The text to display. If the text format is AutoText the text edit will
@@ -869,6 +875,7 @@ void QQuickTextEdit::setHAlign(HAlignment align)
if (d->setHAlign(align, true) && isComponentComplete()) {
d->updateDefaultTextOption();
updateSize();
+ updateWholeDocument();
}
}
@@ -2429,6 +2436,7 @@ void QQuickTextEdit::setDocument(QTextDocument *doc)
d->document = doc;
d->ownsDocument = false;
d->control->setDocument(doc);
+ q_textChanged();
}
inline void resetEngine(QQuickTextNodeEngine *engine, const QColor& textColor, const QColor& selectedTextColor, const QColor& selectionColor)
@@ -3075,8 +3083,11 @@ void QQuickTextEdit::updateSize()
qreal baseline = fm.ascent();
QTextBlock firstBlock = d->document->firstBlock();
- if (firstBlock.isValid() && firstBlock.layout() != nullptr && firstBlock.lineCount() > 0)
- baseline = firstBlock.layout()->lineAt(0).ascent();
+ if (firstBlock.isValid() && firstBlock.layout() != nullptr && firstBlock.lineCount() > 0) {
+ QTextLine firstLine = firstBlock.layout()->lineAt(0);
+ if (firstLine.isValid())
+ baseline = firstLine.ascent();
+ }
setBaselineOffset(baseline + d->yoff + d->textMargin);
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index c013595f45..dd04f1b5be 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -31,7 +31,7 @@
QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
-Q_LOGGING_CATEGORY(lcQuickTextInput, "qt.quick.textInput")
+Q_STATIC_LOGGING_CATEGORY(lcQuickTextInput, "qt.quick.textInput")
/*!
\qmltype TextInput
@@ -405,11 +405,18 @@ QString QQuickTextInputPrivate::realText() const
*/
/*!
- \qmlproperty object QtQuick::TextInput::font.contextFontMerging
+ \qmlproperty bool QtQuick::TextInput::font.contextFontMerging
\since 6.8
\include qquicktext.cpp qml-font-context-font-merging
*/
+
+/*!
+ \qmlproperty bool QtQuick::TextInput::font.preferTypoLineMetrics
+ \since 6.8
+
+ \include qquicktext.cpp qml-font-prefer-typo-line-metrics
+*/
QFont QQuickTextInput::font() const
{
Q_D(const QQuickTextInput);
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index c486fece40..d6d31b4621 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -18,11 +18,10 @@
#include <private/qrawfont_p.h>
#include <private/qglyphrun_p.h>
#include <private/qquickitem_p.h>
+#include <private/qsgdistancefieldglyphnode_p.h>
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcSgText)
-
QQuickTextNodeEngine::BinaryTreeNodeKey::BinaryTreeNodeKey(BinaryTreeNode *node)
: fontEngine(QRawFontPrivate::get(node->glyphRun.rawFont())->fontEngine)
, clipNode(node->clipNode)
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 3392ab075d..9e5b84316b 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -59,13 +59,8 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcHoverTrace)
-Q_DECLARE_LOGGING_CATEGORY(lcMouse)
-Q_DECLARE_LOGGING_CATEGORY(lcTouch)
-Q_DECLARE_LOGGING_CATEGORY(lcPtr)
-Q_LOGGING_CATEGORY(lcDirty, "qt.quick.dirty")
+Q_STATIC_LOGGING_CATEGORY(lcDirty, "qt.quick.dirty")
Q_LOGGING_CATEGORY(lcQuickWindow, "qt.quick.window")
-Q_LOGGING_CATEGORY(lcTransient, "qt.quick.window.transient")
bool QQuickWindowPrivate::defaultAlphaBuffer = false;
@@ -957,9 +952,21 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
// or to cancel the closing.
\endcode
- \note If using \l {Qt Quick Controls}, it's recommended to use
- \l ApplicationWindow instead of Window, as it has better styling
- support.
+ \section1 Styling
+
+ As with all visual types in Qt Quick, Window supports
+ \l {palette}{palettes}. However, as with types like \l Text, Window does
+ not use palettes by default. For example, to change the background color
+ of the window when the operating system's theme changes, the \l color must
+ be set:
+
+ \snippet qml/windowPalette.qml declaration-and-color
+ \codeline
+ \snippet qml/windowPalette.qml text-item
+ \snippet qml/windowPalette.qml closing-brace
+
+ Use \l {ApplicationWindow} (and \l {Label}) from \l {Qt Quick Controls}
+ instead of Window to get automatic styling.
*/
/*!
@@ -1402,41 +1409,6 @@ QObject *QQuickWindow::focusObject() const
return const_cast<QQuickWindow*>(this);
}
-/*!
- \internal
-
- Clears all exclusive and passive grabs for the points in \a pointerEvent.
-
- We never allow any kind of grab to persist after release, unless we're waiting
- for a synth event from QtGui (as with most tablet events), so for points that
- are fully released, the grab is cleared.
-
- Called when QQuickWindow::event dispatches events, or when the QQuickOverlay
- has filtered an event so that it bypasses normal delivery.
-*/
-void QQuickWindowPrivate::clearGrabbers(QPointerEvent *pointerEvent)
-{
- if (pointerEvent->isEndEvent()
- && !(QQuickDeliveryAgentPrivate::isTabletEvent(pointerEvent)
- && (qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)
- || QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse))) {
- if (pointerEvent->isSinglePointEvent()) {
- if (static_cast<QSinglePointEvent *>(pointerEvent)->buttons() == Qt::NoButton) {
- auto &firstPt = pointerEvent->point(0);
- pointerEvent->setExclusiveGrabber(firstPt, nullptr);
- pointerEvent->clearPassiveGrabbers(firstPt);
- }
- } else {
- for (auto &point : pointerEvent->points()) {
- if (point.state() == QEventPoint::State::Released) {
- pointerEvent->setExclusiveGrabber(point, nullptr);
- pointerEvent->clearPassiveGrabbers(point);
- }
- }
- }
- }
-}
-
/*! \reimp */
bool QQuickWindow::event(QEvent *event)
{
@@ -1579,7 +1551,7 @@ bool QQuickWindow::event(QEvent *event)
// or fix QTBUG-90851 so that the event always has points?
bool ret = (da && da->event(event));
- d->clearGrabbers(pe);
+ d->deliveryAgentPrivate()->clearGrabbers(pe);
if (ret)
return true;
@@ -1859,31 +1831,37 @@ void QQuickWindowPrivate::clearFocusObject()
void QQuickWindowPrivate::setFocusToTarget(FocusTarget target, Qt::FocusReason reason)
{
+ if (!contentItem)
+ return;
+
QQuickItem *newFocusItem = nullptr;
- if (contentItem) {
- switch (target) {
- case FocusTarget::First:
- newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(contentItem, true);
- break;
- case FocusTarget::Last:
- newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(contentItem, false);
- break;
- case FocusTarget::Next:
- case FocusTarget::Prev: {
- auto da = deliveryAgentPrivate();
- Q_ASSERT(da);
- QQuickItem *focusItem = da->focusTargetItem() ? da->focusTargetItem() : contentItem;
- bool forward = (target == FocusTarget::Next);
- newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(focusItem, forward);
- break;
- }
- default:
- break;
+ switch (target) {
+ case FocusTarget::First:
+ case FocusTarget::Last: {
+ const bool forward = (target == FocusTarget::First);
+ newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(contentItem, forward);
+ if (newFocusItem) {
+ const auto *itemPriv = QQuickItemPrivate::get(newFocusItem);
+ if (itemPriv->subFocusItem && itemPriv->flags & QQuickItem::ItemIsFocusScope)
+ clearFocusInScope(newFocusItem, itemPriv->subFocusItem, reason);
}
+ break;
+ }
+ case FocusTarget::Next:
+ case FocusTarget::Prev: {
+ const auto da = deliveryAgentPrivate();
+ Q_ASSERT(da);
+ QQuickItem *focusItem = da->focusTargetItem() ? da->focusTargetItem() : contentItem;
+ bool forward = (target == FocusTarget::Next);
+ newFocusItem = QQuickItemPrivate::nextPrevItemInTabFocusChain(focusItem, forward);
+ break;
+ }
+ default:
+ break;
}
if (newFocusItem)
- newFocusItem->setFocus(true, reason);
+ newFocusItem->forceActiveFocus(reason);
}
/*!
@@ -3746,9 +3724,6 @@ void QQuickWindow::endExternalCommands()
the \l Window::flags property with a suitable \l Qt::WindowType (such as
\c Qt::Dialog).
- If a \l{QtQuick::Window::parent}{visual parent} is set on the Window
- the visual parent will take precedence over the transientParent.
-
\sa QtQuick::Window::parent
*/
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 8ba4e56515..07a09ebf70 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -203,8 +203,6 @@ public:
void fireFrameSwapped() { Q_EMIT q_func()->frameSwapped(); }
void fireAboutToStop() { Q_EMIT q_func()->sceneGraphAboutToStop(); }
- void clearGrabbers(QPointerEvent *event);
-
void updateChildWindowStackingOrder(QQuickItem *item = nullptr);
int multiViewCount();
diff --git a/src/quick/items/qquickwindowcontainer.cpp b/src/quick/items/qquickwindowcontainer.cpp
index 839a30330d..cf4209a36b 100644
--- a/src/quick/items/qquickwindowcontainer.cpp
+++ b/src/quick/items/qquickwindowcontainer.cpp
@@ -12,7 +12,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcWindowContainer, "qt.quick.window.container")
+Q_STATIC_LOGGING_CATEGORY(lcWindowContainer, "qt.quick.window.container")
using namespace Qt::StringLiterals;
@@ -21,9 +21,7 @@ using namespace Qt::StringLiterals;
\inqmlmodule QtQuick
\ingroup qtquick-visual
\inherits Item
- \instantiates QQuickItem
- \since 6.7
- \preliminary
+ \since 6.8
\brief Allows embedding arbitrary QWindows into a Qt Quick scene.
@@ -41,10 +39,11 @@ using namespace Qt::StringLiterals;
WindowContainer {
window: foreignWindow
}
- Window {
- parent: someItem
- Item {
- id: siblingItem
+ WindowContainer {
+ window: Window {
+ Item {
+ id: siblingItem
+ }
}
}
}
@@ -60,26 +59,11 @@ using namespace Qt::StringLiterals;
WindowContainer {
id: windowContainer
window: foreignWindow
- Window {
- parent: windowContainer
- Item {
- id: childItem
- }
- }
- }
- }
- \endcode
-
- If positioning and sizing of a Window via anchors is required,
- the Window can be wrapped in a window container:
-
- \code
- Item {
- id: someItem
- WindowContainer {
- anchors.fill: parent
- window: Window {
- Item {
+ WindowContainer {
+ window: Window {
+ Item {
+ id: childItem
+ }
}
}
}
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index e539880452..ddcb588c04 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -22,7 +22,7 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-Q_DECLARE_LOGGING_CATEGORY(lcTransient)
+Q_STATIC_LOGGING_CATEGORY(lcTransient, "qt.quick.window.transient")
QQuickWindowQmlImplPrivate::QQuickWindowQmlImplPrivate() = default;
@@ -286,7 +286,7 @@ bool QQuickWindowQmlImpl::transientParentVisible()
/*!
\qmlproperty var QtQuick::Window::parent
\since 6.7
- \preliminary
+ \internal
This property holds the visual parent of the window.
@@ -492,7 +492,7 @@ int QQuickWindowQmlImpl::y() const
/*!
\qmlproperty real QtQuick::Window::z
- \preliminary
+ \internal
Sets the stacking order of sibling windows.
diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h
index 281c67800e..709e373d0b 100644
--- a/src/quick/items/qquickwindowmodule_p.h
+++ b/src/quick/items/qquickwindowmodule_p.h
@@ -41,10 +41,6 @@ class Q_QUICK_EXPORT QQuickWindowQmlImpl : public QQuickWindow, public QQmlParse
Q_PROPERTY(QWindow::Visibility visibility READ visibility WRITE setVisibility NOTIFY
visibilityChanged)
Q_PROPERTY(QObject *screen READ screen WRITE setScreen NOTIFY screenChanged REVISION(2, 3))
- Q_PROPERTY(QObject *parent READ visualParent WRITE setVisualParent NOTIFY visualParentChanged DESIGNABLE false FINAL REVISION(6, 7))
- Q_PROPERTY(int x READ x WRITE setX NOTIFY xChanged)
- Q_PROPERTY(int y READ y WRITE setY NOTIFY yChanged)
- Q_PROPERTY(qreal z READ z WRITE setZ NOTIFY zChanged FINAL REVISION(6, 7))
QML_ATTACHED(QQuickWindowAttached)
QML_NAMED_ELEMENT(Window)
QML_ADDED_IN_VERSION(2, 1)
@@ -61,6 +57,7 @@ public:
QObject *visualParent() const;
void setVisualParent(QObject *parent);
+ void visualParentChanged(QObject *) {};
void setX(int arg);
int x() const;
@@ -68,18 +65,17 @@ public:
int y() const;
void setZ(qreal arg);
qreal z() const;
+ void zChanged() {};
static QQuickWindowAttached *qmlAttachedProperties(QObject *object);
Q_SIGNALS:
void visibleChanged(bool arg);
void visibilityChanged(QWindow::Visibility visibility);
- Q_REVISION(6, 7) void visualParentChanged(QObject *);
Q_REVISION(2, 3) void screenChanged();
void xChanged(int arg);
void yChanged(int arg);
- Q_REVISION(6, 7) void zChanged();
protected:
void classBegin() override;
diff --git a/src/quick/items/qsginternaltextnode.cpp b/src/quick/items/qsginternaltextnode.cpp
index 6a64c0b9e4..32fde98b9f 100644
--- a/src/quick/items/qsginternaltextnode.cpp
+++ b/src/quick/items/qsginternaltextnode.cpp
@@ -25,8 +25,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcVP)
-
/*!
Creates an empty QSGInternalTextNode
*/
diff --git a/src/quick/jar/CMakeLists.txt b/src/quick/jar/CMakeLists.txt
index 9555bbca16..f6014b2d55 100644
--- a/src/quick/jar/CMakeLists.txt
+++ b/src/quick/jar/CMakeLists.txt
@@ -2,7 +2,16 @@ qt_internal_add_jar(Qt${QtDeclarative_VERSION_MAJOR}AndroidQuick
INCLUDE_JARS
${QT_ANDROID_JAR}
${QT6_INSTALL_PREFIX}/jar/Qt${QtDeclarative_VERSION_MAJOR}Android.jar
- SOURCES org/qtproject/qt/android/QtQuickView.java
+ SOURCES
+ org/qtproject/qt/android/QtQuickView.java
+ org/qtproject/qt/android/QtSignalListener.java
+ org/qtproject/qt/android/QtQmlStatus.java
+ org/qtproject/qt/android/QtQmlStatusChangeListener.java
+ org/qtproject/qt/android/QtModelIndex.java
+ org/qtproject/qt/android/QtAbstractItemModel.java
+ org/qtproject/qt/android/QtAbstractItemModelProxy.java
+ org/qtproject/qt/android/QtQmlComponent.java
+ org/qtproject/qt/android/QtAbstractListModel.java
OUTPUT_DIR "${QT_BUILD_DIR}/jar")
qt_path_join(destination ${INSTALL_DATADIR} "jar")
diff --git a/src/quick/jar/build.gradle b/src/quick/jar/build.gradle
new file mode 100644
index 0000000000..ea6d06c257
--- /dev/null
+++ b/src/quick/jar/build.gradle
@@ -0,0 +1,51 @@
+// This is mainly used to allow Android Studio to easily read this folder as an android project.
+
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:8.4.0'
+ }
+}
+
+apply plugin: 'com.android.library'
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+}
+
+repositories {
+ google()
+ mavenCentral()
+}
+
+android {
+ compileSdk 34
+
+ defaultConfig {
+ minSdkVersion 28
+ }
+
+ sourceSets {
+ main {
+ java.srcDir 'src/'
+ resources.srcDir 'libs/'
+ manifest.srcFile 'AndroidManifest.xml'
+ res.srcDirs = ['res/']
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ android {
+ lintOptions {
+ abortOnError true
+ }
+ }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModel.java b/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModel.java
new file mode 100644
index 0000000000..40c635235f
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModel.java
@@ -0,0 +1,105 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import java.util.HashMap;
+
+public abstract class QtAbstractItemModel
+{
+ public QtAbstractItemModel(){};
+ public abstract int columnCount(QtModelIndex parent);
+ public abstract Object data(QtModelIndex index, int role);
+ public abstract QtModelIndex index(int row, int column, QtModelIndex parent);
+ public abstract QtModelIndex parent(QtModelIndex index);
+ public abstract int rowCount(QtModelIndex parent);
+
+ public native boolean canFetchMore(QtModelIndex parent);
+ public native void fetchMore(QtModelIndex parent);
+ public native boolean hasChildren(QtModelIndex parent);
+ public native boolean hasIndex(int row, int column, QtModelIndex parent);
+
+ public HashMap<Integer, String> roleNames()
+ {
+ return (HashMap<Integer, String>)jni_roleNames();
+ }
+
+ public QtModelIndex sibling(int row, int column, QtModelIndex parent)
+ {
+ return (QtModelIndex)jni_sibling(row, column, parent);
+ }
+
+ protected final void beginInsertColumns(QtModelIndex parent, int first, int last)
+ {
+ jni_beginInsertColumns(parent, first, last);
+ }
+
+ protected final void beginInsertRows(QtModelIndex parent, int first, int last)
+ {
+ jni_beginInsertRows(parent, first, last);
+ }
+ protected final boolean beginMoveColumns(QtModelIndex sourceParent, int sourceFirst,
+ int sourceLast, QtModelIndex destinationParent,
+ int destinationChild)
+ {
+ return jni_beginMoveColumns(sourceParent, sourceFirst, sourceLast, destinationParent,
+ destinationChild);
+ }
+ protected final boolean beginMoveRows(QtModelIndex sourceParent, int sourceFirst,
+ int sourceLast, QtModelIndex destinationParent,
+ int destinationChild)
+ {
+ return jni_beginMoveRows(sourceParent, sourceFirst, sourceLast, destinationParent,
+ destinationChild);
+ }
+ protected final void beginRemoveColumns(QtModelIndex parent, int first, int last)
+ {
+ jni_beginRemoveColumns(parent, first, last);
+ }
+ protected final void beginRemoveRows(QtModelIndex parent, int first, int last)
+ {
+ jni_beginRemoveRows(parent, first, last);
+ }
+ protected final void beginResetModel() { jni_beginResetModel(); }
+
+ protected final QtModelIndex createIndex(int row, int column, long id)
+ {
+ return (QtModelIndex)jni_createIndex(row, column, id);
+ }
+ protected final void endInsertColumns() { jni_endInsertColumns(); }
+ protected final void endInsertRows() { jni_endInsertRows(); }
+ protected final void endMoveColumns() { jni_endMoveColumns(); }
+ protected final void endMoveRows() { jni_endMoveRows(); }
+ protected final void endRemoveColumns() { jni_endRemoveColumns(); }
+ protected final void endRemoveRows() { jni_endRemoveRows(); }
+ protected final void endResetModel() { jni_endResetModel(); }
+
+ private native void jni_beginInsertColumns(QtModelIndex parent, int first, int last);
+ private native void jni_beginInsertRows(QtModelIndex parent, int first, int last);
+ private native boolean jni_beginMoveColumns(QtModelIndex sourceParent, int sourceFirst,
+ int sourceLast, QtModelIndex destinationParent,
+ int destinationChild);
+ private native boolean jni_beginMoveRows(QtModelIndex sourceParent, int sourceFirst,
+ int sourceLast, QtModelIndex destinationParent,
+ int destinationChild);
+ private native void jni_beginRemoveColumns(QtModelIndex parent, int first, int last);
+ private native void jni_beginRemoveRows(QtModelIndex parent, int first, int last);
+ private native void jni_beginResetModel();
+ private native Object jni_createIndex(int row, int column, long id);
+ private native void jni_endInsertColumns();
+ private native void jni_endInsertRows();
+ private native void jni_endMoveColumns();
+ private native void jni_endMoveRows();
+ private native void jni_endRemoveColumns();
+ private native void jni_endRemoveRows();
+ private native void jni_endResetModel();
+ private native Object jni_roleNames();
+ private native Object jni_sibling(int row, int column, QtModelIndex parent);
+
+ private long m_nativeReference = 0;
+ private QtAbstractItemModel(long nativeReference) { m_nativeReference = nativeReference; }
+ private void detachFromNative() { m_nativeReference = 0; };
+ private long nativeReference() { return m_nativeReference; }
+ private void setNativeReference(long nativeReference) { m_nativeReference = nativeReference; }
+ private static boolean instanceOf(Object obj) { return (obj instanceof QtAbstractItemModel); }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModelProxy.java b/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModelProxy.java
new file mode 100644
index 0000000000..6432a3e12e
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModelProxy.java
@@ -0,0 +1,35 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+//
+// 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.
+
+class QtAndroidItemModelProxy extends QtAbstractItemModel
+{
+ @Override public int columnCount(QtModelIndex parent) { return jni_columnCount(parent); };
+ @Override public Object data(QtModelIndex index, int role) { return jni_data(index, role); }
+ @Override public QtModelIndex index(int row, int column, QtModelIndex parent)
+ {
+ return (QtModelIndex)jni_index(row, column, parent);
+ }
+ @Override public QtModelIndex parent(QtModelIndex index)
+ {
+ return (QtModelIndex)jni_parent(index);
+ }
+ @Override public int rowCount(QtModelIndex parent) { return jni_rowCount(parent); }
+
+ private native int jni_columnCount(QtModelIndex parent);
+ private native Object jni_data(QtModelIndex index, int role);
+ private native Object jni_index(int row, int column, QtModelIndex parent);
+ private native Object jni_parent(QtModelIndex index);
+ private native int jni_rowCount(QtModelIndex parent);
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtAbstractListModel.java b/src/quick/jar/org/qtproject/qt/android/QtAbstractListModel.java
new file mode 100644
index 0000000000..5a49caca9c
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtAbstractListModel.java
@@ -0,0 +1,30 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import java.util.HashMap;
+
+public abstract class QtAbstractListModel extends QtAbstractItemModel
+{
+ public QtAbstractListModel(){};
+
+ @Override public final int columnCount(QtModelIndex parent) { return parent.isValid() ? 0 : 1; }
+
+ @Override public QtModelIndex index(int row, int column, QtModelIndex parent)
+ {
+ return hasIndex(row, column, parent) ? createIndex(row, column, 0) : new QtModelIndex();
+ }
+
+ @Override public final QtModelIndex parent(QtModelIndex index) { return new QtModelIndex(); }
+
+ @Override public final boolean hasChildren(QtModelIndex parent)
+ {
+ return parent.isValid() ? false : (rowCount(new QtModelIndex()) > 0);
+ }
+
+ @Override public QtModelIndex sibling(int row, int column, QtModelIndex parent)
+ {
+ return index(row, column, new QtModelIndex());
+ }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtModelIndex.java b/src/quick/jar/org/qtproject/qt/android/QtModelIndex.java
new file mode 100644
index 0000000000..955c736ec4
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtModelIndex.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+public class QtModelIndex
+{
+ public QtModelIndex() { }
+ public int column() { return (int)m_privateData[1]; }
+ public native Object data(int role);
+ public native long internalId();
+ public native boolean isValid();
+ public native QtModelIndex parent();
+ public int row() { return (int)m_privateData[0]; }
+
+ private long[] m_privateData = { -1 /*row*/, -1 /*column*/, 0 /*internalId*/,
+ 0 /*modelReference*/ };
+ private QtModelIndex m_parent = null;
+ private QtModelIndex(int row, int column, long internalId, long modelReference)
+ {
+ m_privateData[0] = row;
+ m_privateData[1] = column;
+ m_privateData[2] = internalId;
+ m_privateData[3] = modelReference;
+ m_parent = null;
+ }
+ private QtModelIndex(int row, int column, QtModelIndex parent, long modelReference)
+ {
+ m_privateData[0] = row;
+ m_privateData[1] = column;
+ m_privateData[2] = 0;
+ m_privateData[3] = modelReference;
+ m_parent = parent;
+ }
+ private void detachFromNative()
+ {
+ m_privateData[0] = -1;
+ m_privateData[1] = -1;
+ m_privateData[2] = 0;
+ m_privateData[3] = 0;
+ };
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQmlComponent.java b/src/quick/jar/org/qtproject/qt/android/QtQmlComponent.java
new file mode 100644
index 0000000000..19d063762e
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtQmlComponent.java
@@ -0,0 +1,206 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.util.Log;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.HashSet;
+
+/**
+ * @Since 6.8
+ *
+ * The QtQmlComponent represents a QML component that can be loaded by a QtQuickView instance
+ * This abstract class should be extended to be used by a QtQuickView. It provides QtQuickView with
+ * essential information to load the QML component it represents.
+ * It also offers convenient methods for seamless interaction with the QtQuickView that loads it.
+ **/
+public abstract class QtQmlComponent
+{
+ private final static String TAG = "QtQmlComponent";
+
+ private WeakReference<QtQuickView> m_viewReference;
+ private QtQmlStatusChangeListener m_statusChangeListener = null;
+ private HashSet<Integer> m_signalListenerIds = new HashSet<>();
+
+ /**
+ * Implement this to return the library name that this component belongs to.
+ **/
+ protected abstract String getLibraryName();
+ /**
+ * Implement this to return the module name that this component belongs to.
+ **/
+ protected abstract String getModuleName();
+ /**
+ * Implement this to return the qrc (Qt Resource) path of this QML component.
+ **/
+ protected abstract String getFilePath();
+
+ /**
+ * Sets a StatusChangeListener to listen to status changes.
+ * <p>
+ * @param listener an instance of a StatusChangeListener interface
+ **/
+ public void setStatusChangeListener(QtQmlStatusChangeListener listener)
+ {
+ m_statusChangeListener = listener;
+ QtQuickView view = getQuickView();
+ if (view != null)
+ view.setStatusChangeListener(listener);
+ }
+
+ /**
+ * Gets the QtQuickView instance that has loaded this component.
+ * <p>
+ * @return Returns an instance of QtQuickView or null if this component is not loaded by any
+ * QtQuickView.
+ **/
+ protected QtQuickView getQuickView()
+ {
+ if (m_viewReference != null)
+ return m_viewReference.get();
+ return null;
+ }
+
+ /**
+ * Checks if this is currently attached to a QtQuickView instance
+ * <p>
+ * @return Returns true if this is attached to a QtQuickView instance, otherwise, returns false.
+ **/
+ protected boolean isViewAttached() { return getQuickView() != null; }
+
+ /**
+ * Attaches this to a QtQuickView instance.
+ **/
+ protected void attachView(QtQuickView view)
+ {
+ m_viewReference = new WeakReference<>(view);
+ if (view != null)
+ view.setStatusChangeListener(m_statusChangeListener);
+ }
+
+ /**
+ * Detaches this from the QtQuickView to which it has previously been attached. A call to this
+ * method will disconnect all signal listeners that have been connected before.
+ **/
+ protected void detachView()
+ {
+ QtQuickView view = getQuickView();
+ if (view != null) {
+ for (int signalListenerId : m_signalListenerIds)
+ view.disconnectSignalListener(signalListenerId);
+
+ view.setStatusChangeListener(null);
+ m_viewReference.clear();
+ if (m_statusChangeListener != null)
+ m_statusChangeListener.onStatusChanged(QtQmlStatus.NULL);
+ }
+ }
+
+ /**
+ * Implement this to return more information about the QML Component.
+ * Default implementation returns an empty HashMap.
+ **/
+ protected HashMap<String, Object> attributes() { return new HashMap<>(); }
+
+ /**
+ * Sets the value of an existing property on the QML component if it has already been attached
+ * and loaded by a QtQuickView instance. The supported types are
+ * {@link java.lang.Integer}, {@link java.lang.Double}, {@link java.lang.Float},
+ * {@link java.lang.Boolean} and {@link java.lang.String}. These types get converted to their
+ * corresponding QML types int, double/float, bool, and string. This function does not add
+ * properties to the QML root object if they do not exist but prints a warning.
+ * <p>
+ * @param propertyName the name of the existing QML property to set the value of
+ * @param value the value to set the property to QML's int, double/float,
+ bool or string
+ * @see <a href="https://doc.qt.io/qt-6/qml-int.html">QML int</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-double.html">QML double/float</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-bool.html">QML bool</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-string.html">QML string</a>
+ **/
+ protected void setProperty(String propertyName, Object value)
+ {
+ QtQuickView view = getQuickView();
+ if (view == null) {
+ Log.w(TAG, "Cannot set property as the QQmlComponent is not loaded in a QtQuickView.");
+ return;
+ }
+ view.setProperty(propertyName, value);
+ }
+
+ /**
+ * Gets the value of an existing property of the QML component if it has already been attached
+ * and loaded by a QtQuickView instance. The supported types are
+ * {@link java.lang.Integer}, {@link java.lang.Double}, {@link java.lang.Float},
+ * {@link java.lang.Boolean} and {@link java.lang.String}. These types get converted to their
+ * corresponding QML types int, double/float, bool and string. If the property does not
+ * exist or the status of the QML component is anything other than
+ * {@link QtQuickView#STATUS_READY STATUS_READY}, this function will return null.
+ * <p>
+ * @param propertyName the name of the existing root object property
+ * @throws ClassCastException if the returned type cannot be cast to the requested type.
+ * @see <a href="https://doc.qt.io/qt-6/qml-int.html">QML int</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-double.html">QML double/float</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-bool.html">QML bool</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-string.html">QML string</a>
+ **/
+ protected <T> T getProperty(String propertyName)
+ {
+ QtQuickView view = getQuickView();
+ if (view == null) {
+ Log.w(TAG, "Cannot get property as the QQmlComponent is not loaded in a QtQuickView.");
+ return null;
+ }
+ return view.<T>getProperty(propertyName);
+ }
+
+ /**
+ * Connects a SignalListener to a signal of the QML component if it has already been attached
+ * and loaded by a QtQuickView instance.
+ * <p>
+ * @param signalName the name of the root object signal
+ * @param argType the Class type of the signal argument
+ * @param listener an instance of the QtSignalListener interface
+ * @return a connection ID between signal and listener or the existing connection ID if there is
+ * an existing connection between the same signal and listener. Return a negative value
+ * if the signal does not exist on the QML root object.
+ **/
+ protected <T> int connectSignalListener(String signalName, Class<T> argType,
+ QtSignalListener<T> listener)
+ {
+ QtQuickView view = getQuickView();
+ if (view == null) {
+ Log.w(TAG,
+ "Cannot connect signal listener as the QQmlComponent is not loaded in a "
+ + "QtQuickView.");
+ return -1;
+ }
+ int signalListenerId = view.connectSignalListener(signalName, argType, listener);
+ m_signalListenerIds.add(signalListenerId);
+ return signalListenerId;
+ }
+
+ /**
+ * Disconnects a SignalListener with a given id obtained from
+ * {@link QtQuickView#connectSignalListener() connectSignalListener} call, from listening to
+ * a signal.
+ * <p>
+ * @param signalListenerId the connection id
+ * @return Returns true if the connection id is valid and has been successfully removed,
+ * otherwise returns false.
+ **/
+ public boolean disconnectSignalListener(int signalListenerId)
+ {
+ QtQuickView view = getQuickView();
+ if (view == null) {
+ Log.w(TAG,
+ "Cannot disconnect signal listener as the QQmlComponent is not loaded in a "
+ + "QtQuickView.");
+ return false;
+ }
+ m_signalListenerIds.remove(signalListenerId);
+ return view.disconnectSignalListener(signalListenerId);
+ }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQmlStatus.java b/src/quick/jar/org/qtproject/qt/android/QtQmlStatus.java
new file mode 100644
index 0000000000..02bea77d43
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtQmlStatus.java
@@ -0,0 +1,49 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import java.lang.IllegalArgumentException;
+
+/**
+ * QtQmlStatus represents the QML component loading status.
+ */
+public enum QtQmlStatus {
+ /**
+ * Not loaded.
+ **/
+ NULL(0),
+
+ /**
+ * Loaded and ready.
+ * Invoking methods that operate on a QML component would succeed <b>only<b> if
+ * the current status is ready.
+ **/
+ READY(1),
+
+ /**
+ *The QML component is getting loaded from network.
+ **/
+ LOADING(2),
+
+ /**
+ * One or more errors has occurred during loading the QML component.
+ **/
+ ERROR(3);
+
+ private final int m_value;
+
+ QtQmlStatus(int value) { this.m_value = value; }
+
+ QtQmlStatus() { this.m_value = ordinal(); }
+
+ static QtQmlStatus fromInt(int value) throws IllegalArgumentException
+ {
+ for (QtQmlStatus enumValue : QtQmlStatus.values()) {
+ if (enumValue.m_value == value) {
+ return enumValue;
+ }
+ }
+ throw new IllegalArgumentException("No QtQmlStatus enum with value " + value);
+ }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQmlStatusChangeListener.java b/src/quick/jar/org/qtproject/qt/android/QtQmlStatusChangeListener.java
new file mode 100644
index 0000000000..f1190ed8b1
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtQmlStatusChangeListener.java
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+/**
+ * A callback that notifies clients about the status of QML component loading.
+ **/
+public interface QtQmlStatusChangeListener
+{
+ /**
+ * Called on the Android UI thread when the QML component status has changed.
+ * @param status The current status. The status can be QtQmlStatus.NULL,
+ * QtQmlStatus.READY, QtQmlStatus.LOADING, or QtQmlStatus.ERROR.
+ **/
+ void onStatusChanged(QtQmlStatus status);
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQuickView.java b/src/quick/jar/org/qtproject/qt/android/QtQuickView.java
index 0f8e999d96..bd4519355f 100644
--- a/src/quick/jar/org/qtproject/qt/android/QtQuickView.java
+++ b/src/quick/jar/org/qtproject/qt/android/QtQuickView.java
@@ -8,6 +8,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.util.Log;
+import java.lang.IllegalArgumentException;
+import java.lang.ref.WeakReference;
import java.security.InvalidParameterException;
/**
@@ -32,62 +34,15 @@ import java.security.InvalidParameterException;
public class QtQuickView extends QtView {
private final static String TAG = "QtQuickView";
- /**
- * A callback that notifies clients when a signal is emitted from the QML root object.
- **/
- @FunctionalInterface
- public interface SignalListener<T>
- {
- /**
- * Called on the Android UI thread when the signal has been emitted.
- * @param signalName literal signal name
- * @param value the value delivered by the signal or null if the signal is parameterless
- **/
- void onSignalEmitted(String signalName, T value);
- }
-
- /**
- * A callback that notifies clients about the status of QML loading.
- **/
- public interface StatusChangeListener
- {
- /**
- * Called on the Android UI thread when the QML component status has changed.
- * @param status The current status. The status can be STATUS_NULL, STATUS_READY,
- * STATUS_LOADING or STATUS_ERROR.
- **/
- void onStatusChanged(int status);
- }
-
- /**
- * QML loading status: No source is set or the root object has not been created yet.
- **/
- public static final int STATUS_NULL = 0;
- /**
- * QML loading status: The QML view is loaded and the root object is available.
- * Invoking methods that operate on the QML root object, i.e.
- * {@link QtQuickView#setProperty() setProperty}, {@link QtQuickView#getProperty() getProperty},
- * and {@link QtQuickView#addSignalListener() addSignalListener} would succeed <b>only<b> if
- * the current status is ready.
- **/
- public static final int STATUS_READY = 1;
- /**
- * QML loading status: The QML view is loading the root object from network.
- **/
- public static final int STATUS_LOADING = 2;
- /**
- * QML loading status: One or more errors has occurred.
- **/
- public static final int STATUS_ERROR = 3;
-
private String m_qmlUri;
private String[] m_qmlImportPaths = null;
- private StatusChangeListener m_statusChangeListener = null;
- private int m_lastStatus = STATUS_NULL;
+ private QtQmlStatusChangeListener m_statusChangeListener = null;
+ private QtQmlStatus m_lastStatus = QtQmlStatus.NULL;
private boolean m_hasQueuedStatus = false;
+ private WeakReference<QtQmlComponent> m_loadedComponent;
native void createQuickView(String qmlUri, int width, int height, long parentWindowReference,
- String[] qmlImportPaths);
+ long viewReference, String[] qmlImportPaths);
native void setRootObjectProperty(long windowReference, String propertyName, Object value);
native Object getRootObjectProperty(long windowReference, String propertyName);
native int addRootObjectSignalListener(long windowReference, String signalName, Class argType,
@@ -138,9 +93,85 @@ public class QtQuickView extends QtView {
m_qmlImportPaths = qmlImportPaths;
}
+ /**
+ * Creates a QtQuickView that can later load and view a QML component by calling
+ * {@link QtQuickView#loadComponent() loadComponent}
+ * <p>
+ * @param context the parent Context
+ **/
+ public QtQuickView(Context context)
+ {
+ super(context);
+ }
+
+ /**
+ * Loads a QML component represented by a QtQmlComponent. The library name and the qrc path of
+ * the QML component will be extracted from the QtQmlComponent to load the QML component.
+ * This overload accepts an array of strings in the case where the QML component should load
+ * QML modules from custom paths.
+ * <p>
+ * @param qmlComponent an instance of an object that extends QtQmlComponent
+ * @param qmlImportPaths an array of strings for additional import paths to be passed to
+ * QQmlEngine, or null if additional import paths are not required
+ * @throws InvalidParameterException if QtQmlComponent does not contain valid information
+ * about the module name, and the qrc path.
+ */
+ // TODO: QTBUG-125620 -- Refresh/reset import paths when loading a new component
+ public <T extends QtQmlComponent> void loadComponent(T qmlComponent, String[] qmlImportPaths)
+ throws InvalidParameterException
+ {
+ String libName = qmlComponent.getLibraryName();
+ String qmlUri = qmlComponent.getFilePath();
+
+ if (libName == null || libName.isEmpty()) {
+ throw new InvalidParameterException(
+ "QtQmlComponent: return value of getLibraryName() may not be empty or null");
+ }
+
+ if (qmlUri == null || qmlUri.isEmpty()) {
+ throw new InvalidParameterException(
+ "QtQmlComponent: return value of getFilePath() may not be empty or null");
+ }
+
+ m_qmlUri = qmlUri;
+ m_qmlImportPaths = qmlImportPaths;
+
+ if (m_loadedComponent != null)
+ m_loadedComponent.clear();
+
+ m_loadedComponent = new WeakReference<>(qmlComponent);
+ qmlComponent.detachView();
+ qmlComponent.attachView(this);
+ // The first QQuickView creation happen after first libs loading
+ // and windowReference() returns a reference to native QQuickView
+ // instance, after that. We don't load library again if the view
+ // exists.
+ if (windowReference() == 0) {
+ loadQtLibraries(libName);
+ } else {
+ createQuickView(m_qmlUri, getWidth(), getHeight(), 0, windowReference(),
+ m_qmlImportPaths);
+ }
+ }
+
+ /**
+ * Loads a QML component represented by a QtQmlComponent. The library name and the qrc path of
+ * the QML component will be extracted from the QtQmlComponent to load the QML component.
+ * <p>
+ * @param qmlComponent an instance of a class that extends QtQmlComponent
+ * @throws InvalidParameterException if QtQmlComponent does not contain valid information
+ * about the module name, and the qrc path.
+ */
+ public <T extends QtQmlComponent> void loadComponent(T qmlComponent)
+ throws InvalidParameterException
+ {
+ loadComponent(qmlComponent, null);
+ }
+
@Override
protected void createWindow(long parentWindowReference) {
- createQuickView(m_qmlUri, getWidth(), getHeight(), parentWindowReference, m_qmlImportPaths);
+ createQuickView(m_qmlUri, getWidth(), getHeight(), parentWindowReference, windowReference(),
+ m_qmlImportPaths);
}
/**
@@ -151,11 +182,12 @@ public class QtQuickView extends QtView {
* properties to the QML root object if they do not exist, but prints a warning.
* <p>
* @param propertyName the name of the existing root object property to set the value of
- * @param value the value to set the property to
- * @see <a href="https://doc.qt.io/qt-6/qml-int.html">QML int</a>,
- * @see <a href="https://doc.qt.io/qt-6/qml-double.html">QML double/float</a>,
- * @see <a href="https://doc.qt.io/qt-6/qml-bool.html">QML bool</a>,
- * @see <a href="https://doc.qt.io/qt-6/qml-string.html">QML string</a>.
+ * @param value the value to set the property to QML's int, double/float, bool or
+ string
+ * @see <a href="https://doc.qt.io/qt-6/qml-int.html">QML int</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-double.html">QML double/float</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-bool.html">QML bool</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-string.html">QML string</a>
**/
public void setProperty(String propertyName, Object value)
{
@@ -172,10 +204,10 @@ public class QtQuickView extends QtView {
* <p>
* @param propertyName the name of the existing root object property
* @throws ClassCastException if the returned type could not be casted to the requested type.
- * @see <a href="https://doc.qt.io/qt-6/qml-int.html">QML int</a>,
- * @see <a href="https://doc.qt.io/qt-6/qml-double.html">QML double/float</a>,
- * @see <a href="https://doc.qt.io/qt-6/qml-bool.html">QML bool</a>,
- * @see <a href="https://doc.qt.io/qt-6/qml-string.html">QML string</a>.
+ * @see <a href="https://doc.qt.io/qt-6/qml-int.html">QML int</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-double.html">QML double/float</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-bool.html">QML bool</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-string.html">QML string</a>
**/
// getRootObjectProperty always returns a primitive type or an Object
// so it is safe to suppress the unchecked warning
@@ -190,13 +222,13 @@ public class QtQuickView extends QtView {
* <p>
* @param signalName the name of the root object signal
* @param argType the Class type of the signal argument
- * @param listener an instance of the SignalListener interface
+ * @param listener an instance of the QtSignalListener interface
* @return a connection id between signal and listener or the existing connection id if there is
* an existing connection between the same signal and listener. Return a negative value
* if the signal does not exists on the QML root object.
**/
public <T> int connectSignalListener(String signalName, Class<T> argType,
- SignalListener<T> listener)
+ QtSignalListener<T> listener)
{
int signalListenerId =
addRootObjectSignalListener(windowReference(), signalName, argType, listener);
@@ -224,25 +256,26 @@ public class QtQuickView extends QtView {
/**
* Gets the status of the QML component.
* <p>
- * @return Returns STATUS_READY when the QML component is ready. Invoking methods that operate
- * on the QML root object ({@link QtQuickView#setProperty() setProperty},
+ * @return Returns QtQmlStatus.READY when the QML component is ready. Invoking methods that
+ * operate on the QML root object ({@link QtQuickView#setProperty() setProperty},
* {@link QtQuickView#getProperty() getProperty}, and
* {@link QtQuickView#addSignalListener() addSignalListener}) would succeed <b>only</b>
- * if the current STATUS_READY. It can also return STATUS_NULL, STATUS_LOADING, or
- * STATUS_ERROR based on the status of see underlaying
- * @see <a href="https://doc.qt.io/qt-6/qquickview.html">QQuickView</a> instance.
+ * if the current status is QtQmlStatus.READY. It can also return QtQmlStatus.NULL,
+ * QtQmlStatus.LOADING, or QtQmlStatus.ERROR based on the status of the underlaying
+ QQuickView instance.
+ * @see <a href="https://doc.qt.io/qt-6/qquickview.html">QQuickView</a>
**/
- public int getStatus()
+ public QtQmlStatus getStatus()
{
return m_lastStatus;
}
/**
- * Sets a StatusChangeListener to listen to status changes.
+ * Sets a QtQmlStatusChangeListener to listen to status changes.
* <p>
- * @param listener an instance of a StatusChangeListener interface
+ * @param listener an instance of a QtQmlStatusChangeListener interface
**/
- public void setStatusChangeListener(StatusChangeListener listener)
+ public void setStatusChangeListener(QtQmlStatusChangeListener listener)
{
m_statusChangeListener = listener;
@@ -254,10 +287,17 @@ public class QtQuickView extends QtView {
private void handleStatusChange(int status)
{
- m_lastStatus = status;
+ try {
+ m_lastStatus = QtQmlStatus.fromInt(status);
+ } catch (IllegalArgumentException e) {
+ m_lastStatus = QtQmlStatus.NULL;
+ e.printStackTrace();
+ }
if (m_statusChangeListener != null)
- QtNative.runAction(() -> { m_statusChangeListener.onStatusChanged(status); });
+ QtNative.runAction(() -> {
+ m_statusChangeListener.onStatusChanged(QtQmlStatus.fromInt(status));
+ });
else
m_hasQueuedStatus = true;
}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc b/src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc
index 26d08e41c4..d603ac4144 100644
--- a/src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc
+++ b/src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc
@@ -62,6 +62,44 @@
For a more detailed example, see \l {QML in Android Studio Projects}.
+ \section1 QtQuickView in an Android Service
+
+ It is also possible to add a QtQuickView from a Service context by using
+ the Android WindowManager interface:
+
+ \code
+ @Override
+ public void onCreate() {
+ m_windowManager = getSystemService(WindowManager.class);
+ m_qtView = new QtQuickView(this, "qrc:/qt/qml/target/main.qml", "target");
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
+ 640, 320,
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
+ PixelFormat.TRANSLUCENT);
+ m_windowManager.addView(m_qtView, layoutParams);
+ }
+ \endcode
+
+ To clean up the QtQuickView and Qt libraries, the onDestroy() lifecycle
+ function can be used:
+
+ \code
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ m_windowManager.removeView(m_qtView);
+ m_qtView = null;
+ }
+ \endcode
+
+ \note Adding a QtQuickView from a Service context requires your application
+ to have the \l {Android: SYSTEM_ALERT_WINDOW}{SYSTEM_ALERT_WINDOW}
+ permission, and to be signed with the platform key.
+
+ \note QML views embedded within a Service context do not
+ support keyboard input or accessibility features.
+
\section1 Constructors
\section2 public QtQuickView(Context parent, String qmlUri, String appName)
diff --git a/src/quick/jar/org/qtproject/qt/android/QtSignalListener.java b/src/quick/jar/org/qtproject/qt/android/QtSignalListener.java
new file mode 100644
index 0000000000..195f983be4
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtSignalListener.java
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+/**
+ * A callback that notifies clients when a signal is emitted from the QML component.
+ **/
+@FunctionalInterface
+public interface QtSignalListener<T> {
+ /**
+ * Called on the Android UI thread when the signal has been emitted.
+ * @param signalName literal signal name
+ * @param value the value delivered by the signal or null if the signal is parameterless
+ **/
+ void onSignalEmitted(String signalName, T value);
+}
diff --git a/src/quick/jar/settings.gradle b/src/quick/jar/settings.gradle
new file mode 100644
index 0000000000..8bf0aad842
--- /dev/null
+++ b/src/quick/jar/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = "QtAndroidQuick"
diff --git a/src/quick/platform/android/qandroiditemmodelproxy.cpp b/src/quick/platform/android/qandroiditemmodelproxy.cpp
new file mode 100644
index 0000000000..4a4653da39
--- /dev/null
+++ b/src/quick/platform/android/qandroiditemmodelproxy.cpp
@@ -0,0 +1,379 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtQuick/private/qandroiditemmodelproxy_p.h>
+#include <QtQuick/private/qandroidmodelindexproxy_p.h>
+#include <QtQuick/private/qandroidtypeconverter_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtJniTypes;
+
+jint QAndroidItemModelProxy::columnCount(const QModelIndex &parent) const
+{
+ Q_ASSERT(jInstance.isValid());
+ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
+ return jInstance.callMethod<jint>("columnCount", parentIndex);
+}
+
+bool QAndroidItemModelProxy::canFetchMore(const QModelIndex &parent) const
+{
+ Q_ASSERT(jInstance.isValid());
+ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
+ return jInstance.callMethod<jboolean>("canFetchMore", parentIndex);
+}
+
+bool QAndroidItemModelProxy::canFetchMoreDefault(const QModelIndex &parent) const
+{
+ return QAbstractItemModel::canFetchMore(parent);
+}
+
+QVariant QAndroidItemModelProxy::data(const QModelIndex &index, int role) const
+{
+ Q_ASSERT(jInstance.isValid());
+ auto jIndex = QAndroidModelIndexProxy::jInstance(index);
+ QJniObject jData = jInstance.callMethod<jobject>("data", jIndex, role);
+ return QAndroidTypeConverter::toQVariant(jData);
+}
+
+QModelIndex QAndroidItemModelProxy::index(int row, int column, const QModelIndex &parent) const
+{
+ Q_ASSERT(jInstance.isValid());
+ JQtModelIndex jIndex = jInstance.callMethod<JQtModelIndex>(
+ "index", row, column, QAndroidModelIndexProxy::jInstance(parent));
+ return QAndroidModelIndexProxy::qInstance(jIndex);
+}
+
+QModelIndex QAndroidItemModelProxy::parent(const QModelIndex &index) const
+{
+ Q_ASSERT(jInstance.isValid());
+
+ auto jIndex = QAndroidModelIndexProxy::jInstance(index);
+ return QAndroidModelIndexProxy::qInstance(
+ jInstance.callMethod<JQtModelIndex>("parent", jIndex));
+}
+int QAndroidItemModelProxy::rowCount(const QModelIndex &parent) const
+{
+ Q_ASSERT(jInstance.isValid());
+
+ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
+ return jInstance.callMethod<int>("rowCount", parentIndex);
+}
+
+QHash<int, QByteArray> QAndroidItemModelProxy::roleNames() const
+{
+ Q_ASSERT(jInstance.isValid());
+
+ QHash<int, QByteArray> roleNames;
+ HashMap hashMap = jInstance.callMethod<HashMap>("roleNames");
+ Set set = hashMap.callMethod<Set>("keySet");
+ QJniArray<jobject> keyArray = set.callMethod<QJniArray<jobject>>("toArray");
+
+ for (auto key : keyArray) {
+ const QJniObject roleName = hashMap.callMethod<jobject>("get", key);
+ const int intKey = QJniObject(key).callMethod<jint>("intValue");
+ const QByteArray roleByteArray = String(roleName).toString().toLatin1();
+ roleNames.insert(intKey, roleByteArray);
+ }
+ return roleNames;
+}
+
+QHash<int, QByteArray> QAndroidItemModelProxy::defaultRoleNames() const
+{
+ return QAbstractItemModel::roleNames();
+}
+
+void QAndroidItemModelProxy::fetchMore(const QModelIndex &parent)
+{
+ Q_ASSERT(jInstance.isValid());
+ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
+ jInstance.callMethod<void>("fetchMore", parentIndex);
+}
+
+void QAndroidItemModelProxy::fetchMoreDefault(const QModelIndex &parent)
+{
+ QAbstractItemModel::fetchMore(parent);
+}
+
+bool QAndroidItemModelProxy::hasChildren(const QModelIndex &parent) const
+{
+ Q_ASSERT(jInstance.isValid());
+ auto parentIndex = QAndroidModelIndexProxy::jInstance(parent);
+ return jInstance.callMethod<jboolean>("hasChildren", parentIndex);
+}
+
+bool QAndroidItemModelProxy::hasChildrenDefault(const QModelIndex &parent) const
+{
+ return QAbstractItemModel::hasChildren(parent);
+}
+
+QModelIndex QAndroidItemModelProxy::sibling(int row, int column, const QModelIndex &parent) const
+{
+ Q_ASSERT(jInstance.isValid());
+ return QAndroidModelIndexProxy::qInstance(jInstance.callMethod<jobject>(
+ "sibling", row, column, QAndroidModelIndexProxy::jInstance(parent)));
+}
+
+QModelIndex QAndroidItemModelProxy::siblingDefault(int row, int column, const QModelIndex &parent)
+{
+ return QAbstractItemModel::sibling(row, column, parent);
+}
+
+Q_REQUIRED_RESULT QAbstractItemModel *
+QAndroidItemModelProxy::nativeInstance(JQtAbstractItemModel itemModel)
+{
+ jlong nativeReference = itemModel.callMethod<jlong>("nativeReference");
+ return reinterpret_cast<QAbstractItemModel *>(nativeReference);
+}
+
+Q_REQUIRED_RESULT QAbstractItemModel *
+QAndroidItemModelProxy::createNativeProxy(QJniObject itemModel)
+{
+ QAbstractItemModel *nativeProxy = nativeInstance(itemModel);
+ if (!nativeProxy) {
+ nativeProxy = new QAndroidItemModelProxy(itemModel);
+
+ itemModel.callMethod<void>("setNativeReference", reinterpret_cast<jlong>(nativeProxy));
+ connect(nativeProxy, &QAndroidItemModelProxy::destroyed, nativeProxy, [](QObject *obj) {
+ auto proxy = qobject_cast<QAndroidItemModelProxy *>(obj);
+ if (proxy)
+ proxy->jInstance.callMethod<void>("detachFromNative");
+ });
+ }
+ return nativeProxy;
+}
+
+QJniObject QAndroidItemModelProxy::createProxy(QAbstractItemModel *itemModel)
+{
+ return JQtAndroidItemModelProxy(reinterpret_cast<jlong>(itemModel));
+}
+
+int QAndroidItemModelProxy::jni_columnCount(JNIEnv *env, jobject object, JQtModelIndex parent)
+{
+ const QModelIndex nativeParent = QAndroidModelIndexProxy::qInstance(parent);
+ return invokeNativeMethod(env, object, &QAbstractItemModel::columnCount, nativeParent);
+}
+
+jobject QAndroidItemModelProxy::jni_data(JNIEnv *env, jobject object, JQtModelIndex index,
+ jint role)
+{
+ const QModelIndex nativeIndex = QAndroidModelIndexProxy::qInstance(index);
+ const QVariant data =
+ invokeNativeMethod(env, object, &QAbstractItemModel::data, nativeIndex, role);
+ return QAndroidTypeConverter::toJavaObject(data, env);
+}
+
+jobject QAndroidItemModelProxy::jni_index(JNIEnv *env, jobject object, jint row, jint column,
+ JQtModelIndex parent)
+{
+ auto nativeParent = QAndroidModelIndexProxy::qInstance(parent);
+ const QModelIndex modelIndex =
+ invokeNativeMethod(env, object, &QAbstractItemModel::index, row, column, nativeParent);
+ return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(modelIndex).object());
+}
+
+jobject QAndroidItemModelProxy::jni_parent(JNIEnv *env, jobject object, JQtModelIndex index)
+{
+ const QModelIndex nativeIndex = QAndroidModelIndexProxy::qInstance(index);
+ QModelIndex (QAbstractItemModel::*parentOverloadPtr)(const QModelIndex &) const =
+ &QAbstractItemModel::parent;
+ const QModelIndex parent = invokeNativeMethod(env, object, parentOverloadPtr, nativeIndex);
+ return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(parent).object());
+}
+
+jint QAndroidItemModelProxy::jni_rowCount(JNIEnv *env, jobject object, JQtModelIndex parent)
+{
+ return invokeNativeMethod(env, object, &QAbstractItemModel::rowCount,
+ QAndroidModelIndexProxy::qInstance(parent));
+}
+
+jobject QAndroidItemModelProxy::jni_roleNames(JNIEnv *env, jobject object)
+{
+ auto roleNames = invokeNativeImpl(env, object, &QAndroidItemModelProxy::defaultRoleNames,
+ &QAbstractItemModel::roleNames);
+ HashMap jRoleNames{};
+ for (auto [role, roleName] : roleNames.asKeyValueRange()) {
+ const Integer jRole(role);
+ const QJniObject jRoleName = QJniObject::fromString(roleName);
+ jRoleNames.callMethod<jobject>("put", jRole.object(), jRoleName.object());
+ }
+ return env->NewLocalRef(jRoleNames.object());
+}
+
+jobject QAndroidItemModelProxy::jni_createIndex(JNIEnv *env, jobject object, jint row, jint column,
+ jlong id)
+{
+ QModelIndex (QAndroidItemModelProxy::*createIndexPtr)(int, int, quintptr) const =
+ &QAndroidItemModelProxy::createIndex;
+ const QModelIndex index = invokeNativeProxyMethod(env, object, createIndexPtr, row, column, id);
+ return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(index).object());
+}
+
+jboolean QAndroidItemModelProxy::jni_canFetchMore(JNIEnv *env, jobject object, JQtModelIndex parent)
+{
+ return invokeNativeImpl(env, object, &QAndroidItemModelProxy::canFetchMoreDefault,
+ &QAbstractItemModel::canFetchMore,
+ QAndroidModelIndexProxy::qInstance(parent));
+}
+
+void QAndroidItemModelProxy::jni_fetchMore(JNIEnv *env, jobject object, JQtModelIndex parent)
+{
+ return invokeNativeImpl(env, object, &QAndroidItemModelProxy::fetchMoreDefault,
+ &QAbstractItemModel::fetchMore,
+ QAndroidModelIndexProxy::qInstance(parent));
+}
+
+jboolean QAndroidItemModelProxy::jni_hasChildren(JNIEnv *env, jobject object, JQtModelIndex parent)
+{
+ return invokeNativeImpl(env, object, &QAndroidItemModelProxy::hasChildrenDefault,
+ &QAbstractItemModel::hasChildren,
+ QAndroidModelIndexProxy::qInstance(parent));
+}
+
+jboolean QAndroidItemModelProxy::jni_hasIndex(JNIEnv *env, jobject object, jint row, jint column,
+ JQtModelIndex parent)
+{
+ return invokeNativeMethod(env, object, &QAbstractItemModel::hasIndex, row, column,
+ QAndroidModelIndexProxy::qInstance(parent));
+}
+
+void QAndroidItemModelProxy::jni_beginInsertColumns(JNIEnv *env, jobject object,
+ JQtModelIndex parent, jint first, jint last)
+{
+
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginInsertColumns,
+ QAndroidModelIndexProxy::qInstance(parent), first, last);
+}
+
+void QAndroidItemModelProxy::jni_beginInsertRows(JNIEnv *env, jobject object, JQtModelIndex parent,
+ jint first, jint last)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginInsertRows,
+ QAndroidModelIndexProxy::qInstance(parent), first, last);
+}
+
+jboolean QAndroidItemModelProxy::jni_beginMoveColumns(JNIEnv *env, jobject object,
+ JQtModelIndex sourceParent, jint sourceFirst,
+ jint sourceLast,
+ JQtModelIndex destinationParent,
+ jint destinationChild)
+{
+ return invokeNativeProxyMethod(
+ env, object, &QAndroidItemModelProxy::beginMoveColumns,
+ QAndroidModelIndexProxy::qInstance(sourceParent), sourceFirst, sourceLast,
+ QAndroidModelIndexProxy::qInstance(destinationParent), destinationChild);
+}
+
+jboolean QAndroidItemModelProxy::jni_beginMoveRows(JNIEnv *env, jobject object,
+ JQtModelIndex sourceParent, jint sourceFirst,
+ jint sourceLast, JQtModelIndex destinationParent,
+ jint destinationChild)
+{
+ return invokeNativeProxyMethod(
+ env, object, &QAndroidItemModelProxy::beginMoveRows,
+ QAndroidModelIndexProxy::qInstance(sourceParent), sourceFirst, sourceLast,
+ QAndroidModelIndexProxy::qInstance(destinationParent), destinationChild);
+}
+
+void QAndroidItemModelProxy::jni_beginRemoveColumns(JNIEnv *env, jobject object,
+ JQtModelIndex parent, jint first, jint last)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginRemoveColumns,
+ QAndroidModelIndexProxy::qInstance(parent), first, last);
+}
+
+void QAndroidItemModelProxy::jni_beginRemoveRows(JNIEnv *env, jobject object, JQtModelIndex parent,
+ jint first, jint last)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginRemoveRows,
+ QAndroidModelIndexProxy::qInstance(parent), first, last);
+}
+
+void QAndroidItemModelProxy::jni_beginResetModel(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::beginResetModel);
+}
+
+void QAndroidItemModelProxy::jni_endInsertColumns(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endInsertColumns);
+}
+
+void QAndroidItemModelProxy::jni_endInsertRows(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endInsertRows);
+}
+
+void QAndroidItemModelProxy::jni_endMoveColumns(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endMoveColumns);
+}
+
+void QAndroidItemModelProxy::jni_endMoveRows(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endMoveRows);
+}
+
+void QAndroidItemModelProxy::jni_endRemoveColumns(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endRemoveColumns);
+}
+
+void QAndroidItemModelProxy::jni_endRemoveRows(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endRemoveRows);
+}
+
+void QAndroidItemModelProxy::jni_endResetModel(JNIEnv *env, jobject object)
+{
+ invokeNativeProxyMethod(env, object, &QAndroidItemModelProxy::endResetModel);
+}
+
+jobject QAndroidItemModelProxy::jni_sibling(JNIEnv *env, jobject object, jint row, jint column,
+ JQtModelIndex parent)
+{
+ const QModelIndex index = invokeNativeImpl(env, object, &QAndroidItemModelProxy::siblingDefault,
+ &QAbstractItemModel::sibling, row, column,
+ QAndroidModelIndexProxy::qInstance(parent));
+ return env->NewLocalRef(QAndroidModelIndexProxy::jInstance(index).object());
+}
+
+bool QAndroidItemModelProxy::registerAbstractNatives(QJniEnvironment &env)
+{
+ return env.registerNativeMethods(
+ Traits<JQtAbstractItemModel>::className(),
+ { Q_JNI_NATIVE_SCOPED_METHOD(jni_roleNames, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_canFetchMore, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_createIndex, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_fetchMore, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_hasChildren, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_hasIndex, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginInsertColumns, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginInsertRows, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginMoveColumns, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginMoveRows, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginRemoveColumns, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginRemoveRows, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_beginResetModel, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endInsertColumns, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endInsertRows, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endMoveColumns, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endMoveRows, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endRemoveColumns, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endRemoveRows, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_endResetModel, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_sibling, QAndroidItemModelProxy) });
+}
+
+bool QAndroidItemModelProxy::registerProxyNatives(QJniEnvironment &env)
+{
+ return env.registerNativeMethods(
+ Traits<JQtAndroidItemModelProxy>::className(),
+ { Q_JNI_NATIVE_SCOPED_METHOD(jni_columnCount, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_data, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_index, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_parent, QAndroidItemModelProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(jni_rowCount, QAndroidItemModelProxy) });
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/platform/android/qandroiditemmodelproxy_p.h b/src/quick/platform/android/qandroiditemmodelproxy_p.h
new file mode 100644
index 0000000000..6670395596
--- /dev/null
+++ b/src/quick/platform/android/qandroiditemmodelproxy_p.h
@@ -0,0 +1,191 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDITEMMODELPROXY_P_H
+#define QANDROIDITEMMODELPROXY_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 <QtQuick/private/qandroidmodelindexproxy_p.h>
+#include <QtQuick/private/qandroidtypes_p.h>
+#include <QtQuick/private/qtquickglobal_p.h>
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjnitypes.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_EXPORT QAndroidItemModelProxy : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ explicit QAndroidItemModelProxy(QtJniTypes::JQtAbstractItemModel jInstance)
+ : jInstance(jInstance)
+ {
+ }
+
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QModelIndex index(int row, int column,
+ const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex &index) const override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ bool canFetchMore(const QModelIndex &parent) const override;
+ bool canFetchMoreDefault(const QModelIndex &parent) const;
+ QHash<int, QByteArray> roleNames() const override;
+ QHash<int, QByteArray> defaultRoleNames() const;
+ void fetchMore(const QModelIndex &parent) override;
+ void fetchMoreDefault(const QModelIndex &parent);
+ bool hasChildren(const QModelIndex &parent) const override;
+ bool hasChildrenDefault(const QModelIndex &parent) const;
+ QModelIndex sibling(int row, int column, const QModelIndex &parent) const override;
+ QModelIndex siblingDefault(int row, int column, const QModelIndex &parent);
+
+ Q_REQUIRED_RESULT static QAbstractItemModel *
+ nativeInstance(QtJniTypes::JQtAbstractItemModel itemModel);
+ Q_REQUIRED_RESULT static QAbstractItemModel *createNativeProxy(QJniObject itemModel);
+ static QJniObject createProxy(QAbstractItemModel *abstractClass);
+
+ template <typename Func, typename... Args>
+ static auto invokeNativeProxyMethod(JNIEnv */*env*/, jobject jvmObject, Func func, Args &&...args)
+ {
+ Q_ASSERT(jvmObject);
+ auto model = qobject_cast<QAndroidItemModelProxy *>(nativeInstance(jvmObject));
+ Q_ASSERT(model);
+ return std::invoke(func, model, std::forward<Args>(args)...);
+ }
+
+ template <typename Func, typename... Args>
+ static auto invokeNativeMethod(JNIEnv */*env*/, jobject jvmObject, Func func, Args &&...args)
+ {
+ Q_ASSERT(jvmObject);
+ auto model = nativeInstance(jvmObject);
+ Q_ASSERT(model);
+ return std::invoke(func, model, std::forward<Args>(args)...);
+ }
+
+ template <typename Func1, typename Func2, typename... Args>
+ static auto invokeNativeImpl(JNIEnv */*env*/, jobject jvmObject, Func1 defaultFunc, Func2 func,
+ Args &&...args)
+ {
+ Q_ASSERT(jvmObject);
+ auto nativeModel = nativeInstance(jvmObject);
+ auto nativeProxyModel = qobject_cast<QAndroidItemModelProxy *>(nativeModel);
+ if (nativeProxyModel)
+ return std::invoke(defaultFunc, nativeProxyModel, std::forward<Args>(args)...);
+ else
+ return std::invoke(func, nativeModel, std::forward<Args>(args)...);
+ }
+
+ static jint jni_columnCount(JNIEnv *env, jobject object, JQtModelIndex parent);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_columnCount)
+
+ static jobject jni_data(JNIEnv *env, jobject object, JQtModelIndex index, jint role);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_data)
+
+ static jobject jni_index(JNIEnv *env, jobject object, jint row, jint column,
+ JQtModelIndex parent);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_index)
+
+ static jobject jni_parent(JNIEnv *env, jobject object, JQtModelIndex index);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_parent)
+
+ static jint jni_rowCount(JNIEnv *env, jobject object, JQtModelIndex parent);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_rowCount)
+
+ static jboolean jni_canFetchMore(JNIEnv *env, jobject object, JQtModelIndex parent);
+ QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(jni_canFetchMore, canFetchMore)
+
+ static void jni_fetchMore(JNIEnv *env, jobject object, JQtModelIndex parent);
+ QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(jni_fetchMore, fetchMore)
+
+ static jboolean jni_hasChildren(JNIEnv *env, jobject object, JQtModelIndex parent);
+ QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(jni_hasChildren, hasChildren)
+
+ static jboolean jni_hasIndex(JNIEnv *env, jobject object, jint row, jint column,
+ JQtModelIndex parent);
+ QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(jni_hasIndex, hasIndex)
+
+ static jobject jni_roleNames(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_roleNames)
+
+ static void jni_beginInsertColumns(JNIEnv *env, jobject object, JQtModelIndex parent,
+ jint first, jint last);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginInsertColumns)
+
+ static void jni_beginInsertRows(JNIEnv *env, jobject object, JQtModelIndex parent, jint first,
+ jint last);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginInsertRows)
+
+ static jboolean jni_beginMoveColumns(JNIEnv *env, jobject object, JQtModelIndex sourceParent,
+ jint sourceFirst, jint sourceLast,
+ JQtModelIndex destinationParent, jint destinationChild);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginMoveColumns)
+
+ static jboolean jni_beginMoveRows(JNIEnv *env, jobject object, JQtModelIndex sourceParent,
+ jint sourceFirst, jint sourceLast,
+ JQtModelIndex destinationParent, jint destinationChild);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginMoveRows)
+
+ static void jni_beginRemoveColumns(JNIEnv *env, jobject object, JQtModelIndex parent,
+ jint first, jint last);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginRemoveColumns)
+
+ static void jni_beginRemoveRows(JNIEnv *env, jobject object, JQtModelIndex parent, jint first,
+ jint last);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginRemoveRows)
+
+ static void jni_beginResetModel(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_beginResetModel)
+
+ static jobject jni_createIndex(JNIEnv *env, jobject object, jint row, jint column, jlong id);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_createIndex)
+
+ static void jni_endInsertColumns(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endInsertColumns)
+
+ static void jni_endInsertRows(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endInsertRows)
+
+ static void jni_endMoveColumns(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endMoveColumns)
+
+ static void jni_endMoveRows(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endMoveRows)
+
+ static void jni_endRemoveColumns(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endRemoveColumns)
+
+ static void jni_endRemoveRows(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endRemoveRows)
+
+ static void jni_endResetModel(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_endResetModel)
+
+ static jobject jni_sibling(JNIEnv *env, jobject object, jint row, jint column,
+ JQtModelIndex parent);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_sibling)
+
+ static bool registerAbstractNatives(QJniEnvironment &env);
+ static bool registerProxyNatives(QJniEnvironment &env);
+
+private:
+ QJniObject jInstance;
+ friend class QAndroidModelIndexProxy;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDITEMMODELPROXY_P_H
diff --git a/src/quick/platform/android/qandroidmodelindexproxy.cpp b/src/quick/platform/android/qandroidmodelindexproxy.cpp
new file mode 100644
index 0000000000..b749d9f344
--- /dev/null
+++ b/src/quick/platform/android/qandroidmodelindexproxy.cpp
@@ -0,0 +1,103 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtQuick/private/qandroiditemmodelproxy_p.h>
+#include <QtQuick/private/qandroidmodelindexproxy_p.h>
+#include <QtQuick/private/qandroidtypeconverter_p.h>
+
+#include <QtCore/qjniarray.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtJniTypes;
+
+QModelIndex QAndroidModelIndexProxy::qInstance(JQtModelIndex jModelIndex)
+{
+ if (!jModelIndex.isValid())
+ return QModelIndex();
+
+ const QJniArray<jlong> jPrivateArray = jModelIndex.getField<jlong[]>("m_privateData");
+ const auto privateData = jPrivateArray.toContainer();
+ Q_ASSERT(privateData.size() == 4);
+
+ const jlong modelReference = privateData[3];
+ if (!modelReference)
+ return QModelIndex();
+
+ const jint row = privateData[0];
+ const jint column = privateData[1];
+ QAbstractItemModel *model = reinterpret_cast<QAbstractItemModel *>(modelReference);
+ QAndroidItemModelProxy *proxyModel = qobject_cast<QAndroidItemModelProxy *>(model);
+
+ // If the native model instance is a proxy we have access to the protected function
+ // createIndex(). Else, if the native instance is not a results Java->Qt proxy, we
+ // use index() to get the QModelIndex.
+ if (proxyModel) {
+ const jint internalId = privateData[2];
+ return proxyModel->createIndex(row, column, internalId);
+ } else {
+ const JQtModelIndex parent = jModelIndex.getField<JQtModelIndex>("m_parent");
+ if (parent.isValid())
+ return model->index(row, column, QAndroidModelIndexProxy::qInstance(parent));
+ }
+ return QModelIndex();
+}
+
+JQtModelIndex QAndroidModelIndexProxy::jInstance(QModelIndex modelIndex)
+{
+ if (!modelIndex.isValid())
+ return JQtModelIndex();
+ bool isModelProxy = qobject_cast<const QAndroidItemModelProxy *>(modelIndex.model());
+ if (isModelProxy)
+ return JQtModelIndex(modelIndex.row(), modelIndex.column(), modelIndex.internalId(),
+ reinterpret_cast<jlong>(modelIndex.model()));
+ else
+ return JQtModelIndex(modelIndex.row(), modelIndex.column(),
+ QAndroidModelIndexProxy::jInstance(modelIndex.parent()),
+ reinterpret_cast<jlong>(modelIndex.model()));
+}
+
+jobject QAndroidModelIndexProxy::data(JNIEnv *env, jobject object, int role)
+{
+ Q_ASSERT(env);
+ Q_ASSERT(object);
+
+ QModelIndex modelIndex = qInstance(object);
+ if (!modelIndex.isValid())
+ return nullptr;
+
+ return QAndroidTypeConverter::toJavaObject(modelIndex.model()->data(modelIndex, role), env);
+}
+
+jlong QAndroidModelIndexProxy::internalId(JNIEnv *env, jobject object)
+{
+ Q_ASSERT(env);
+ Q_ASSERT(object);
+ return qInstance(object).internalId();
+};
+
+jboolean QAndroidModelIndexProxy::isValid(JNIEnv *env, jobject object)
+{
+ Q_ASSERT(env);
+ Q_ASSERT(object);
+ return qInstance(object).isValid();
+}
+
+JQtModelIndex QAndroidModelIndexProxy::parent(JNIEnv *env, jobject object)
+{
+ Q_ASSERT(env);
+ Q_ASSERT(object);
+ return jInstance(qInstance(object).parent());
+};
+
+bool QAndroidModelIndexProxy::registerNatives(QJniEnvironment &env)
+{
+ return env.registerNativeMethods(
+ Traits<JQtModelIndex>::className(),
+ { Q_JNI_NATIVE_SCOPED_METHOD(data, QAndroidModelIndexProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(internalId, QAndroidModelIndexProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(isValid, QAndroidModelIndexProxy),
+ Q_JNI_NATIVE_SCOPED_METHOD(parent, QAndroidModelIndexProxy) });
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/platform/android/qandroidmodelindexproxy_p.h b/src/quick/platform/android/qandroidmodelindexproxy_p.h
new file mode 100644
index 0000000000..05db788652
--- /dev/null
+++ b/src/quick/platform/android/qandroidmodelindexproxy_p.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDMODELINDEXPROXY_P_H
+#define QANDROIDMODELINDEXPROXY_P_H
+
+#include <QtQuick/private/qandroidtypes_p.h>
+#include <QtQuick/private/qtquickglobal_p.h>
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjnitypes.h>
+#include <QDebug>
+
+//
+// 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.
+//
+
+QT_BEGIN_NAMESPACE
+
+using namespace QtJniTypes;
+
+class QAndroidItemModelProxy;
+
+class Q_QUICK_EXPORT QAndroidModelIndexProxy
+{
+public:
+ static JQtModelIndex jInstance(QModelIndex modelIndex);
+ static QModelIndex qInstance(JQtModelIndex jModelIndex);
+
+ static jobject data(JNIEnv *env, jobject object, int role);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(data)
+
+ static jlong internalId(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(internalId)
+
+ static jboolean isValid(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(isValid)
+
+ static JQtModelIndex parent(JNIEnv *env, jobject object);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(parent)
+
+ static bool registerNatives(QJniEnvironment &env);
+};
+
+QT_BEGIN_NAMESPACE
+
+#endif // QANDROIDMODELINDEXPROXY_P_H
diff --git a/src/quick/platform/android/qandroidquickviewembedding.cpp b/src/quick/platform/android/qandroidquickviewembedding.cpp
index 8b25ff0deb..262dd9179c 100644
--- a/src/quick/platform/android/qandroidquickviewembedding.cpp
+++ b/src/quick/platform/android/qandroidquickviewembedding.cpp
@@ -2,6 +2,11 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtQuick/private/qandroidquickviewembedding_p.h>
+#include <QtQuick/private/qandroidtypes_p.h>
+#include <QtQuick/private/qandroidtypeconverter_p.h>
+#include <QtQuick/private/qandroidviewsignalmanager_p.h>
+#include <QtQuick/private/qandroiditemmodelproxy_p.h>
+#include <QtQuick/private/qandroidmodelindexproxy_p.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qjnienvironment.h>
@@ -18,70 +23,71 @@ Q_DECLARE_JNI_CLASS(QtQuickView, "org/qtproject/qt/android/QtQuickView");
Q_DECLARE_JNI_CLASS(QtWindow, "org/qtproject/qt/android/QtWindow");
Q_DECLARE_JNI_CLASS(View, "android/view/View");
-Q_DECLARE_JNI_CLASS(Void, "java/lang/Void");
-Q_DECLARE_JNI_CLASS(Integer, "java/lang/Integer");
-Q_DECLARE_JNI_CLASS(Double, "java/lang/Double");
-Q_DECLARE_JNI_CLASS(Float, "java/lang/Float");
-Q_DECLARE_JNI_CLASS(Boolean, "java/lang/Boolean");
-Q_DECLARE_JNI_CLASS(String, "java/lang/String");
-Q_DECLARE_JNI_CLASS(Class, "java/lang/Class");
-
namespace QtAndroidQuickViewEmbedding
{
- void createQuickView(JNIEnv*, jobject nativeWindow, jstring qmlUri, jint width, jint height,
- jlong parentWindowReference, QtJniTypes::StringArray qmlImportPaths)
+ constexpr const char *uninitializedViewMessage = "because QtQuickView is not loaded or ready yet.";
+
+ void createQuickView(JNIEnv *, jobject nativeWindow, jstring qmlUri, jint width, jint height,
+ jlong parentWindowReference, jlong viewReference,
+ const QJniArray<jstring> &qmlImportPaths)
{
static_assert (sizeof(jlong) >= sizeof(void*),
"Insufficient size of Java type to hold the c++ pointer");
const QUrl qmlUrl(QJniObject(qmlUri).toString());
- QStringList importPaths;
- if (qmlImportPaths.isValid()) {
- QJniArray<QtJniTypes::String> importPathsArray(qmlImportPaths);
- importPaths.reserve(importPathsArray.size());
- for (int i = 0; i < importPathsArray.size(); ++i)
- importPaths << importPathsArray.at(i).toString();
- }
-
+ const QStringList importPaths = qmlImportPaths.toContainer();
QMetaObject::invokeMethod(qApp, [qtViewObject = QJniObject(nativeWindow),
parentWindowReference,
+ viewReference,
width,
height,
qmlUrl,
importPaths] {
- QWindow *parentWindow = reinterpret_cast<QWindow *>(parentWindowReference);
- QQuickView *view = new QQuickView(parentWindow);
- QQmlEngine *engine = view->engine();
- new SignalHelper(view);
- QObject::connect(view, &QQuickView::statusChanged,
- [qtViewObject](QQuickView::Status status) {
- qtViewObject.callMethod<void>("handleStatusChange", status);
- });
- view->setResizeMode(QQuickView::SizeRootObjectToView);
- view->setColor(QColor(Qt::transparent));
- view->setWidth(width);
- view->setHeight(height);
- for (const QString &path : importPaths)
- engine->addImportPath(path);
-
- const QtJniTypes::QtWindow window = reinterpret_cast<jobject>(view->winId());
- qtViewObject.callMethod<void>("addQtWindow",
- window,
- reinterpret_cast<jlong>(view),
- parentWindowReference);
+ // If the view does not exists (viewReference==0) we should create and set it up.
+ // Else we only reset the source of the view.
+ QAndroidQuickView *view = reinterpret_cast<QAndroidQuickView *>(viewReference);
+ if (!view) {
+ QWindow *parentWindow = reinterpret_cast<QWindow *>(parentWindowReference);
+ view = new QAndroidQuickView(parentWindow);
+ QObject::connect(view, &QAndroidQuickView::statusChanged, view,
+ [qtViewObject](QAndroidQuickView::Status status) {
+ qtViewObject.callMethod<void>("handleStatusChange", status);
+ });
+ view->setResizeMode(QAndroidQuickView::SizeRootObjectToView);
+ view->setColor(QColor(Qt::transparent));
+ view->setWidth(width);
+ view->setHeight(height);
+ QQmlEngine *engine = view->engine();
+ for (const QString &path : importPaths)
+ engine->addImportPath(path);
+
+ const QtJniTypes::QtWindow window = reinterpret_cast<jobject>(view->winId());
+ qtViewObject.callMethod<void>("addQtWindow",
+ window,
+ reinterpret_cast<jlong>(view),
+ parentWindowReference);
+ }
view->setSource(qmlUrl);
});
}
+ std::pair<QAndroidQuickView *, QQuickItem *> getViewAndRootObject(jlong windowReference)
+ {
+ QAndroidQuickView *view = reinterpret_cast<QAndroidQuickView *>(windowReference);
+ QQuickItem *rootObject = Q_LIKELY(view) ? view->rootObject() : nullptr;
+ return std::make_pair(view, rootObject);
+ }
+
void setRootObjectProperty(JNIEnv *env, jobject object, jlong windowReference,
jstring propertyName, jobject value)
{
Q_UNUSED(env);
Q_UNUSED(object);
- QQuickItem *rootObject = reinterpret_cast<QQuickView *>(windowReference)->rootObject();
+ auto [_, rootObject] = getViewAndRootObject(windowReference);
if (!rootObject) {
- qWarning() << "QtQuickView instance does not own a root object.";
+ qWarning("Cannot set property %s %s", qPrintable(QJniObject(propertyName).toString()),
+ uninitializedViewMessage);
return;
}
@@ -95,20 +101,14 @@ namespace QtAndroidQuickViewEmbedding
QMetaProperty metaProperty = rootMetaObject->property(propertyIndex);
const QJniObject propertyValue(value);
- const QByteArray valueClassname = propertyValue.className();
-
- if (valueClassname == QtJniTypes::Traits<QtJniTypes::String>::className())
- metaProperty.write(rootObject, propertyValue.toString());
- else if (valueClassname == QtJniTypes::Traits<QtJniTypes::Integer>::className())
- metaProperty.write(rootObject, propertyValue.callMethod<jint>("intValue"));
- else if (valueClassname == QtJniTypes::Traits<QtJniTypes::Double>::className())
- metaProperty.write(rootObject, propertyValue.callMethod<jdouble>("doubleValue"));
- else if (valueClassname == QtJniTypes::Traits<QtJniTypes::Float>::className())
- metaProperty.write(rootObject, propertyValue.callMethod<jfloat>("floatValue"));
- else if (valueClassname == QtJniTypes::Traits<QtJniTypes::Boolean>::className())
- metaProperty.write(rootObject, propertyValue.callMethod<jboolean>("booleanValue"));
- else
- qWarning("Setting the property type of %s is not supported.", valueClassname.data());
+ const QVariant variantToWrite = QAndroidTypeConverter::toQVariant(propertyValue);
+
+ if (!variantToWrite.isValid()) {
+ qWarning("Setting the property type of %s is not supported.",
+ qPrintable(propertyValue.className()));
+ } else {
+ metaProperty.write(rootObject, variantToWrite);
+ }
}
jobject getRootObjectProperty(JNIEnv *env, jobject object, jlong windowReference,
@@ -118,54 +118,28 @@ namespace QtAndroidQuickViewEmbedding
Q_ASSERT(env);
const QString property = QJniObject(propertyName).toString();
- QQuickView *view = reinterpret_cast<QQuickView *>(windowReference);
- QQuickItem *rootObject = view->rootObject();
+ auto [_, rootObject] = getViewAndRootObject(windowReference);
if (!rootObject) {
- qWarning("Cannot read property %s as the QtQuickView instance (%s)"
- "does not own a root object.",
- qPrintable(property),
- qPrintable(view->source().toString()));
+ qWarning("Cannot get property %s %s", qPrintable(property), uninitializedViewMessage);
return nullptr;
}
const QMetaObject *rootMetaObject = rootObject->metaObject();
int propertyIndex = rootMetaObject->indexOfProperty(property.toUtf8().constData());
if (propertyIndex < 0) {
- qWarning("Cannot read property %s as it does not exist in the root QML object.",
+ qWarning("Cannot get property %s as it does not exist in the root QML object.",
qPrintable(property));
return nullptr;
}
QMetaProperty metaProperty = rootMetaObject->property(propertyIndex);
- QVariant propertyValue = metaProperty.read(rootObject);
- const int propertyTypeId = propertyValue.typeId();
-
- switch (propertyTypeId) {
- case QMetaType::Type::Int:
- return env->NewLocalRef(
- QJniObject::construct<QtJniTypes::Integer>(get<int>(std::move(propertyValue)))
- .object());
- case QMetaType::Type::Double:
- return env->NewLocalRef(
- QJniObject::construct<QtJniTypes::Double>(get<double>(std::move(propertyValue)))
- .object());
- case QMetaType::Type::Float:
- return env->NewLocalRef(
- QJniObject::construct<QtJniTypes::Float>(get<float>(std::move(propertyValue)))
- .object());
- case QMetaType::Type::Bool:
- return env->NewLocalRef(
- QJniObject::construct<QtJniTypes::Boolean>(get<bool>(std::move(propertyValue)))
- .object());
- case QMetaType::Type::QString:
- return env->NewLocalRef(
- QJniObject::fromString(get<QString>(std::move(propertyValue))).object());
- default:
+ const QVariant propertyValue = metaProperty.read(rootObject);
+ jobject jObject = QAndroidTypeConverter::toJavaObject(propertyValue, env);
+ if (!jObject) {
qWarning("Property %s cannot be converted to a supported Java data type.",
qPrintable(property));
}
-
- return nullptr;
+ return jObject;
}
int addRootObjectSignalListener(JNIEnv *env, jobject, jlong windowReference, jstring signalName,
@@ -181,18 +155,14 @@ namespace QtAndroidQuickViewEmbedding
{ "java/lang/Boolean", QMetaType::Type::Bool }
};
- QQuickView *view = reinterpret_cast<QQuickView *>(windowReference);
- if (!view) {
- qWarning() << "QtQuickView is not loaded or ready yet.";
- return -1;
- }
- QQuickItem *rootObject = view->rootObject();
+ auto [view, rootObject] = getViewAndRootObject(windowReference);
if (!rootObject) {
- qWarning() << "QtQuickView instance does not own a root object.";
+ qWarning("Cannot connect to signal %s %s",
+ qPrintable(QJniObject(signalName).toString()), uninitializedViewMessage);
return -1;
}
- SignalHelper *signalHelper = view->findChild<SignalHelper *>();
+ QAndroidViewSignalManager *signalManager = view->signalManager();
const QByteArray javaArgClass = QJniObject(argType).className();
const char *qArgName =
QMetaType(javaToQMetaType.value(javaArgClass, QMetaType::Type::UnknownType)).name();
@@ -231,7 +201,7 @@ namespace QtAndroidQuickViewEmbedding
if (signalIndex == -1)
return -1;
- const QMetaObject *helperMetaObject = signalHelper->metaObject();
+ const QMetaObject *helperMetaObject = signalManager->metaObject();
QByteArray helperSignalSignature = signalSignature;
helperSignalSignature.replace(0, signalSignature.indexOf('('), "forwardSignal");
int helperSlotIndex = helperMetaObject->indexOfSlot(helperSignalSignature.constData());
@@ -240,15 +210,17 @@ namespace QtAndroidQuickViewEmbedding
// Return the id if the signal is already connected to the same listener.
QJniObject listenerJniObject(listener);
- if (signalHelper->listenersMap.contains(signalSignature)) {
- auto listenerInfos = signalHelper->listenersMap.values(signalSignature);
- auto isSameListener = [listenerJniObject](const SignalHelper::ListenerInfo &listenerInfo) {
- return listenerInfo.listener == listenerJniObject;
- };
- auto iterator = std::find_if(listenerInfos.constBegin(),
- listenerInfos.constEnd(),
+ if (signalManager->connectionInfoMap.contains(signalSignature)) {
+ auto connectionInfos = signalManager->connectionInfoMap.values(signalSignature);
+ auto isSameListener =
+ [listenerJniObject](
+ const QAndroidViewSignalManager::ConnectionInfo &connectionInfo) {
+ return connectionInfo.listener == listenerJniObject;
+ };
+ auto iterator = std::find_if(connectionInfos.constBegin(),
+ connectionInfos.constEnd(),
isSameListener);
- if (iterator != listenerInfos.end()) {
+ if (iterator != connectionInfos.end()) {
qWarning("Signal listener with the ID of %i is already connected to %s signal.",
iterator->id,
signalSignature.constData());
@@ -258,52 +230,52 @@ namespace QtAndroidQuickViewEmbedding
QMetaMethod signalMethod = metaObject->method(signalIndex);
QMetaMethod signalForwarderMethod = helperMetaObject->method(helperSlotIndex);
- signalHelper->connectionHandleCounter++;
+ signalManager->connectionHandleCounter++;
QMetaObject::Connection connection;
- if (signalHelper->listenersMap.contains(signalSignature)) {
- connection = signalHelper
- ->connections[signalHelper->listenersMap.value(signalSignature).id];
+ if (signalManager->connectionInfoMap.contains(signalSignature)) {
+ const int existingId = signalManager->connectionInfoMap.value(signalSignature).id;
+ connection = signalManager->connections[existingId];
} else {
connection = QObject::connect(rootObject,
signalMethod,
- signalHelper,
+ signalManager,
signalForwarderMethod);
}
- SignalHelper::ListenerInfo listenerInfo;
- listenerInfo.listener = listenerJniObject;
- listenerInfo.javaArgType = javaArgClass;
- listenerInfo.propertyIndex = propertyIndex;
- listenerInfo.signalSignature = signalSignature;
- listenerInfo.id = signalHelper->connectionHandleCounter;
+ QAndroidViewSignalManager::ConnectionInfo connectionInfo;
+ connectionInfo.listener = listenerJniObject;
+ connectionInfo.javaArgType = javaArgClass;
+ connectionInfo.propertyIndex = propertyIndex;
+ connectionInfo.signalSignature = signalSignature;
+ connectionInfo.id = signalManager->connectionHandleCounter;
- signalHelper->listenersMap.insert(signalSignature, listenerInfo);
- signalHelper->connections.insert(listenerInfo.id, connection);
+ signalManager->connectionInfoMap.insert(signalSignature, connectionInfo);
+ signalManager->connections.insert(connectionInfo.id, connection);
- return listenerInfo.id;
+ return connectionInfo.id;
}
bool removeRootObjectSignalListener(JNIEnv *, jobject, jlong windowReference,
jint signalListenerId)
{
- QQuickView *view = reinterpret_cast<QQuickView *>(windowReference);
- QQuickItem *rootObject = view->rootObject();
+ auto [view, rootObject] = getViewAndRootObject(windowReference);
if (!rootObject) {
- qWarning() << "QtQuickView instance does not own a root object.";
+ qWarning("Cannot disconnect the signal connection with id: %i %s", signalListenerId,
+ uninitializedViewMessage);
return false;
}
- SignalHelper *signalHelper = view->findChild<SignalHelper *>();
- if (!signalHelper->connections.contains(signalListenerId))
+ QAndroidViewSignalManager *signalManager = view->signalManager();
+ if (!signalManager->connections.contains(signalListenerId))
return false;
QByteArray signalSignature;
- for (auto listenerInfoIter = signalHelper->listenersMap.begin();
- listenerInfoIter != signalHelper->listenersMap.end();) {
+ for (auto listenerInfoIter = signalManager->connectionInfoMap.begin();
+ listenerInfoIter != signalManager->connectionInfoMap.end();) {
if (listenerInfoIter->id == signalListenerId) {
signalSignature = listenerInfoIter->signalSignature;
- signalHelper->listenersMap.erase(listenerInfoIter);
+ signalManager->connectionInfoMap.erase(listenerInfoIter);
break;
} else {
++listenerInfoIter;
@@ -311,98 +283,13 @@ namespace QtAndroidQuickViewEmbedding
}
// disconnect if its the last listener associated with the signal signatures
- if (!signalHelper->listenersMap.contains(signalSignature))
- rootObject->disconnect(signalHelper->connections.value(signalListenerId));
+ if (!signalManager->connectionInfoMap.contains(signalSignature))
+ rootObject->disconnect(signalManager->connections.value(signalListenerId));
- signalHelper->connections.remove(signalListenerId);
+ signalManager->connections.remove(signalListenerId);
return true;
}
- void SignalHelper::forwardSignal()
- {
- invokeListener(sender(), senderSignalIndex(), QVariant());
- }
-
- void SignalHelper::forwardSignal(int signalValue)
- {
- invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
- }
-
- void SignalHelper::forwardSignal(bool signalValue)
- {
- invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
- }
-
- void SignalHelper::forwardSignal(double signalValue)
- {
- invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
- }
-
- void SignalHelper::forwardSignal(float signalValue)
- {
- invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
- }
-
- void SignalHelper::forwardSignal(QString signalValue)
- {
- invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
- }
-
- void SignalHelper::invokeListener(QObject *sender, int senderSignalIndex, QVariant signalValue)
- {
- using namespace QtJniTypes;
-
- const QMetaObject *metaObject = sender->metaObject();
- const QMetaMethod signalMethod = metaObject->method(senderSignalIndex);
-
- for (auto listenerInfoIter = listenersMap.constFind(signalMethod.methodSignature());
- listenerInfoIter != listenersMap.constEnd() &&
- listenerInfoIter.key() == signalMethod.methodSignature();
- ++listenerInfoIter) {
- const ListenerInfo listenerInfo = *listenerInfoIter;
- const QByteArray javaArgType = listenerInfo.javaArgType;
- QJniObject jSignalMethodName =
- QJniObject::fromString(QLatin1StringView(signalMethod.name()));
-
- if (listenerInfo.propertyIndex != -1 && javaArgType != Traits<Void>::className())
- signalValue = metaObject->property(listenerInfo.propertyIndex).read(sender);
-
- int valueTypeId = signalValue.typeId();
- QJniObject jValue;
-
- switch (valueTypeId) {
- case QMetaType::Type::UnknownType:
- break;
- case QMetaType::Type::Int:
- jValue = qVariantToJniObject<Integer,jint>(signalValue);
- break;
- case QMetaType::Type::Double:
- jValue = qVariantToJniObject<Double,jdouble>(signalValue);
- break;
- case QMetaType::Type::Float:
- jValue = qVariantToJniObject<Float,jfloat>(signalValue);
- break;
- case QMetaType::Type::Bool:
- jValue = qVariantToJniObject<Boolean,jboolean>(signalValue);
- break;
- case QMetaType::Type::QString:
- jValue = QJniObject::fromString(get<QString>(std::move(signalValue)));
- break;
- default:
- qWarning("Mismatching argument types between QML signal (%s) and the Java function "
- "(%s). Sending null as argument.",
- signalMethod.methodSignature().constData(), javaArgType.constData());
- }
-
- QNativeInterface::QAndroidApplication::runOnAndroidMainThread(
- [listenerInfo, jSignalMethodName, jValue]() {
- listenerInfo.listener.callMethod<void, jstring, jobject>("onSignalEmitted",
- jSignalMethodName.object<jstring>(),
- jValue.object());
- });
- }
- }
-
bool registerNatives(QJniEnvironment& env) {
return env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtQuickView>::className(),
{Q_JNI_NATIVE_SCOPED_METHOD(createQuickView,
@@ -433,6 +320,12 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
return JNI_ERR;
if (!QtAndroidQuickViewEmbedding::registerNatives(env))
return JNI_ERR;
+ if (!QAndroidItemModelProxy::registerAbstractNatives(env))
+ return JNI_ERR;
+ if (!QAndroidItemModelProxy::registerProxyNatives(env))
+ return JNI_ERR;
+ if (!QAndroidModelIndexProxy::registerNatives(env))
+ return JNI_ERR;
return JNI_VERSION_1_6;
}
diff --git a/src/quick/platform/android/qandroidquickviewembedding_p.h b/src/quick/platform/android/qandroidquickviewembedding_p.h
index ace387a7f1..43ff997264 100644
--- a/src/quick/platform/android/qandroidquickviewembedding_p.h
+++ b/src/quick/platform/android/qandroidquickviewembedding_p.h
@@ -15,19 +15,20 @@
// We mean it.
//
+#include <QtQuick/private/qandroidviewsignalmanager_p.h>
+
#include <QtCore/qjnienvironment.h>
#include <QtCore/qjnitypes.h>
#include <QtQuick/qquickview.h>
QT_BEGIN_NAMESPACE
-Q_DECLARE_JNI_TYPE(StringArray, "[Ljava/lang/String;")
-
namespace QtAndroidQuickViewEmbedding
{
bool registerNatives(QJniEnvironment& env);
void createQuickView(JNIEnv *env, jobject nativeWindow, jstring qmlUri, jint width, jint height,
- jlong parentWindowReference, QtJniTypes::StringArray qmlImportPaths);
+ jlong parentWindowReference, jlong viewReference,
+ const QJniArray<jstring> &qmlImportPaths);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(createQuickView)
void setRootObjectProperty(JNIEnv *env, jobject, jlong parentWindowReference,
jstring propertyName, jobject value);
@@ -42,38 +43,17 @@ namespace QtAndroidQuickViewEmbedding
jint signalListenerId);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(removeRootObjectSignalListener)
- class SignalHelper : public QObject
+ class QAndroidQuickView : public QQuickView
{
Q_OBJECT
+ std::unique_ptr<QAndroidViewSignalManager> m_signalManager;
+
public:
- struct ListenerInfo
+ explicit QAndroidQuickView(QWindow *parent)
+ : QQuickView(parent), m_signalManager(new QAndroidViewSignalManager())
{
- ListenerInfo() : propertyIndex(-1) { }
- int id;
- QJniObject listener;
- QByteArray javaArgType;
- QByteArray signalSignature;
- int propertyIndex;
- };
-
- int connectionHandleCounter;
- explicit SignalHelper(QQuickView *parent) : QObject(parent), connectionHandleCounter(0) { }
- QMultiMap<QByteArray, ListenerInfo> listenersMap;
- QHash<int, QMetaObject::Connection> connections;
- void invokeListener(QObject *sender, int senderSignalIndex, QVariant signalValue);
-
- template<typename JT, typename T>
- inline QJniObject qVariantToJniObject(const QVariant& v) {
- return QJniObject(QtJniTypes::Traits<JT>::className(), get<T>(std::move(v)));
- };
-
- public slots:
- void forwardSignal();
- void forwardSignal(int);
- void forwardSignal(double);
- void forwardSignal(float);
- void forwardSignal(bool);
- void forwardSignal(QString);
+ }
+ inline QAndroidViewSignalManager *signalManager() const { return m_signalManager.get(); };
};
};
diff --git a/src/quick/platform/android/qandroidtypeconverter_p.h b/src/quick/platform/android/qandroidtypeconverter_p.h
new file mode 100644
index 0000000000..1bde5a5464
--- /dev/null
+++ b/src/quick/platform/android/qandroidtypeconverter_p.h
@@ -0,0 +1,99 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDTYPECONVERTER_P_H
+#define QANDROIDTYPECONVERTER_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 <QtQuick/private/qandroidtypes_p.h>
+#include <QtQuick/private/qandroiditemmodelproxy_p.h>
+
+#include <QtCore/qjniobject.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjnitypes.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QAndroidTypeConverter
+{
+ [[maybe_unused]] static QVariant toQVariant(const QJniObject &object)
+ {
+ using namespace QtJniTypes;
+ if (!object.isValid())
+ return QVariant{};
+ const QByteArray classname(object.className());
+
+ if (classname == Traits<String>::className())
+ return object.toString();
+ else if (classname == Traits<Integer>::className())
+ return object.callMethod<jint>("intValue");
+ else if (classname == Traits<Long>::className())
+ return QVariant::fromValue<long>(object.callMethod<jlong>("longValue"));
+ else if (classname == Traits<Double>::className())
+ return object.callMethod<jdouble>("doubleValue");
+ else if (classname == Traits<Float>::className())
+ return object.callMethod<jfloat>("floatValue");
+ else if (classname == Traits<Boolean>::className())
+ return QVariant::fromValue<bool>(object.callMethod<jboolean>("booleanValue"));
+ else {
+ QJniEnvironment env;
+ const jclass className = env.findClass(Traits<JQtAbstractItemModel>::className());
+ if (env->IsInstanceOf(object.object(), className))
+ return QVariant::fromValue(QAndroidItemModelProxy::createNativeProxy(object));
+ }
+
+ return QVariant{};
+ }
+
+ [[maybe_unused]] Q_REQUIRED_RESULT static jobject toJavaObject(const QVariant &var, JNIEnv *env)
+ {
+ Q_ASSERT(env);
+ switch (var.typeId()) {
+ case QMetaType::Type::Int:
+ return env->NewLocalRef(QJniObject::construct<QtJniTypes::Integer>(
+ get<int>(var))
+ .object());
+ case QMetaType::Type::Long:
+ case QMetaType::Type::LongLong:
+ return env->NewLocalRef(QJniObject::construct<QtJniTypes::Long>(
+ get<jlong>(var))
+ .object());
+ case QMetaType::Type::Double:
+ return env->NewLocalRef(QJniObject::construct<QtJniTypes::Double>(
+ get<double>(var))
+ .object());
+ case QMetaType::Type::Float:
+ return env->NewLocalRef(QJniObject::construct<QtJniTypes::Float>(
+ get<float>(var))
+ .object());
+ case QMetaType::Type::Bool:
+ return env->NewLocalRef(QJniObject::construct<QtJniTypes::Boolean>(
+ get<bool>(var))
+ .object());
+ case QMetaType::Type::QString:
+ return env->NewLocalRef(
+ QJniObject::fromString(get<QString>(var)).object());
+ default:
+ if (var.canConvert<QAbstractItemModel *>()) {
+ return env->NewLocalRef(
+ QAndroidItemModelProxy::createProxy(var.value<QAbstractItemModel *>())
+ .object());
+ } else
+ return nullptr;
+ }
+ return nullptr;
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDTYPECONVERTER_P_H
diff --git a/src/quick/platform/android/qandroidtypes_p.h b/src/quick/platform/android/qandroidtypes_p.h
new file mode 100644
index 0000000000..e2c25f6965
--- /dev/null
+++ b/src/quick/platform/android/qandroidtypes_p.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDTYPES_P_H
+#define QANDROIDTYPES_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 <QtCore/qjniobject.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjnitypes.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_DECLARE_JNI_CLASS_STANDARD_TYPES
+Q_DECLARE_JNI_CLASS(Void, "java/lang/Void");
+Q_DECLARE_JNI_CLASS(Integer, "java/lang/Integer");
+Q_DECLARE_JNI_CLASS(Long, "java/lang/Long");
+Q_DECLARE_JNI_CLASS(Double, "java/lang/Double");
+Q_DECLARE_JNI_CLASS(Float, "java/lang/Float");
+Q_DECLARE_JNI_CLASS(Boolean, "java/lang/Boolean");
+Q_DECLARE_JNI_CLASS(String, "java/lang/String");
+Q_DECLARE_JNI_CLASS(Class, "java/lang/Class");
+
+Q_DECLARE_JNI_CLASS(HashMap, "java/util/HashMap")
+Q_DECLARE_JNI_CLASS(Set, "java/util/Set")
+#endif
+
+Q_DECLARE_JNI_CLASS(JQtAbstractItemModel, "org/qtproject/qt/android/QtAbstractItemModel")
+Q_DECLARE_JNI_CLASS(JQtAndroidItemModelProxy, "org/qtproject/qt/android/QtAndroidItemModelProxy")
+Q_DECLARE_JNI_CLASS(JQtModelIndex, "org/qtproject/qt/android/QtModelIndex")
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDTYPES_P_H
diff --git a/src/quick/platform/android/qandroidviewsignalmanager.cpp b/src/quick/platform/android/qandroidviewsignalmanager.cpp
new file mode 100644
index 0000000000..9fb5fc4ec5
--- /dev/null
+++ b/src/quick/platform/android/qandroidviewsignalmanager.cpp
@@ -0,0 +1,77 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtQuick/private/qandroidtypeconverter_p.h>
+#include <QtQuick/private/qandroidviewsignalmanager_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QAndroidViewSignalManager::forwardSignal()
+{
+ invokeListener(sender(), senderSignalIndex(), QVariant());
+}
+
+void QAndroidViewSignalManager::forwardSignal(int signalValue)
+{
+ invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
+}
+
+void QAndroidViewSignalManager::forwardSignal(bool signalValue)
+{
+ invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
+}
+
+void QAndroidViewSignalManager::forwardSignal(double signalValue)
+{
+ invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
+}
+
+void QAndroidViewSignalManager::forwardSignal(float signalValue)
+{
+ invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
+}
+
+void QAndroidViewSignalManager::forwardSignal(QString signalValue)
+{
+ invokeListener(sender(), senderSignalIndex(), QVariant(signalValue));
+}
+
+void QAndroidViewSignalManager::invokeListener(QObject *sender, int senderSignalIndex,
+ QVariant signalValue)
+{
+ using namespace QtJniTypes;
+
+ const QMetaObject *metaObject = sender->metaObject();
+ const QMetaMethod signalMethod = metaObject->method(senderSignalIndex);
+
+ for (auto connectionInfoIter = connectionInfoMap.constFind(signalMethod.methodSignature());
+ connectionInfoIter != connectionInfoMap.constEnd()
+ && connectionInfoIter.key() == signalMethod.methodSignature();
+ ++connectionInfoIter) {
+ const ConnectionInfo connectionInfo = *connectionInfoIter;
+ const QByteArray javaArgType = connectionInfo.javaArgType;
+ QJniObject jSignalMethodName =
+ QJniObject::fromString(QLatin1StringView(signalMethod.name()));
+
+ if (connectionInfo.propertyIndex != -1 && javaArgType != Traits<Void>::className())
+ signalValue = metaObject->property(connectionInfo.propertyIndex).read(sender);
+
+ QJniObject jValue(
+ QAndroidTypeConverter::toJavaObject(signalValue, QJniEnvironment::getJniEnv()));
+
+ if (!jValue.isValid()) {
+ qWarning("Mismatching argument types between QML signal (%s) and the Java function "
+ "(%s). Sending null as argument.",
+ signalMethod.methodSignature().constData(), javaArgType.constData());
+ }
+
+ QNativeInterface::QAndroidApplication::runOnAndroidMainThread(
+ [connectionInfo, jSignalMethodName, jValue]() {
+ connectionInfo.listener.callMethod<void, jstring, jobject>(
+ "onSignalEmitted", jSignalMethodName.object<jstring>(),
+ jValue.object());
+ });
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/platform/android/qandroidviewsignalmanager_p.h b/src/quick/platform/android/qandroidviewsignalmanager_p.h
new file mode 100644
index 0000000000..c6ca6543b3
--- /dev/null
+++ b/src/quick/platform/android/qandroidviewsignalmanager_p.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDVIEWSIGNALMANAGER_P_H
+#define QANDROIDVIEWSIGNALMANAGER_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 <QtCore/qobject.h>
+#include <QtCore/qjnitypes.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidViewSignalManager : public QObject
+{
+ Q_OBJECT
+public:
+ struct ConnectionInfo
+ {
+ int id;
+ QJniObject listener;
+ QByteArray javaArgType;
+ QByteArray signalSignature;
+ int propertyIndex{ -1 };
+ };
+
+ explicit QAndroidViewSignalManager()
+ : QObject(), connectionHandleCounter(0)
+ {
+ }
+ void invokeListener(QObject *sender, int senderSignalIndex, QVariant signalValue);
+
+ int connectionHandleCounter;
+ QMultiMap<QByteArray, ConnectionInfo> connectionInfoMap;
+ QHash<int, QMetaObject::Connection> connections;
+
+public slots:
+ void forwardSignal();
+ void forwardSignal(int);
+ void forwardSignal(double);
+ void forwardSignal(float);
+ void forwardSignal(bool);
+ void forwardSignal(QString);
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDVIEWSIGNALMANAGER_P_H
diff --git a/src/quick/qtquickglobal_p.h b/src/quick/qtquickglobal_p.h
index 835aeb2aa9..89d2e31942 100644
--- a/src/quick/qtquickglobal_p.h
+++ b/src/quick/qtquickglobal_p.h
@@ -33,7 +33,6 @@ void Q_QUICK_EXPORT QQuick_initializeModule();
Q_DECLARE_LOGGING_CATEGORY(lcTouch)
Q_DECLARE_LOGGING_CATEGORY(lcMouse)
Q_DECLARE_LOGGING_CATEGORY(lcFocus)
-Q_DECLARE_LOGGING_CATEGORY(lcDirty)
/*
This is needed for QuickTestUtils. Q_AUTOTEST_EXPORT checks QT_BUILDING_QT
diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
index c9385630d9..0c2af5e23b 100644
--- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp
@@ -12,7 +12,7 @@
#include <QtGui/QWindow>
#include <QtQuick/QSGSimpleRectNode>
-Q_LOGGING_CATEGORY(lc2DRender, "qt.scenegraph.softwarecontext.abstractrenderer")
+Q_STATIC_LOGGING_CATEGORY(lc2DRender, "qt.scenegraph.softwarecontext.abstractrenderer")
QT_BEGIN_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
index d269b1ac67..02592ad155 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp
@@ -8,7 +8,7 @@
#include <QElapsedTimer>
-Q_LOGGING_CATEGORY(lcPixmapRenderer, "qt.scenegraph.softwarecontext.pixmapRenderer")
+Q_STATIC_LOGGING_CATEGORY(lcPixmapRenderer, "qt.scenegraph.softwarecontext.pixmapRenderer")
QT_BEGIN_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
index 79fa4a78ad..33874b4061 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp
@@ -20,7 +20,7 @@
#include <qmath.h>
-Q_LOGGING_CATEGORY(lcRenderable, "qt.scenegraph.softwarecontext.renderable")
+Q_STATIC_LOGGING_CATEGORY(lcRenderable, "qt.scenegraph.softwarecontext.renderable")
QT_BEGIN_NAMESPACE
diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
index df4ec592c3..b078277ad4 100644
--- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
+++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp
@@ -12,7 +12,7 @@
#include <QtGui/QBackingStore>
#include <QElapsedTimer>
-Q_LOGGING_CATEGORY(lcRenderer, "qt.scenegraph.softwarecontext.renderer")
+Q_STATIC_LOGGING_CATEGORY(lcRenderer, "qt.scenegraph.softwarecontext.renderer")
QT_BEGIN_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 5746d984bf..6c084ec441 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -2710,6 +2710,8 @@ bool Renderer::ensurePipelineState(Element *e, const ShaderManager::Shader *sms,
blend.dstColor = m_gstate.dstColor;
blend.srcAlpha = m_gstate.srcAlpha;
blend.dstAlpha = m_gstate.dstAlpha;
+ blend.opColor = m_gstate.opColor;
+ blend.opAlpha = m_gstate.opAlpha;
ps->setTargetBlends({ blend });
ps->setDepthTest(m_gstate.depthTest);
@@ -2841,6 +2843,7 @@ static void rendererToMaterialGraphicsState(QSGMaterialShader::GraphicsPipelineS
// the enum values should match, sanity check it
Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::OneMinusSrc1Alpha) == int(QRhiGraphicsPipeline::OneMinusSrc1Alpha));
+ Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::BlendOpMax) == int(QRhiGraphicsPipeline::Max));
Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::A) == int(QRhiGraphicsPipeline::A));
Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::CullBack) == int(QRhiGraphicsPipeline::Back));
Q_ASSERT(int(QSGMaterialShader::GraphicsPipelineState::Line) == int(QRhiGraphicsPipeline::Line));
@@ -2858,6 +2861,9 @@ static void rendererToMaterialGraphicsState(QSGMaterialShader::GraphicsPipelineS
dst->srcAlpha = QSGMaterialShader::GraphicsPipelineState::BlendFactor(src->srcAlpha);
dst->dstAlpha = QSGMaterialShader::GraphicsPipelineState::BlendFactor(src->dstAlpha);
+ dst->opColor = QSGMaterialShader::GraphicsPipelineState::BlendOp(src->opColor);
+ dst->opAlpha = QSGMaterialShader::GraphicsPipelineState::BlendOp(src->opAlpha);
+
dst->colorWrite = QSGMaterialShader::GraphicsPipelineState::ColorMask(int(src->colorWrite));
dst->cullMode = QSGMaterialShader::GraphicsPipelineState::CullMode(src->cullMode);
@@ -2877,6 +2883,8 @@ static void materialToRendererGraphicsState(GraphicsState *dst,
dst->srcAlpha = dst->srcColor;
dst->dstAlpha = dst->dstColor;
}
+ dst->opColor = QRhiGraphicsPipeline::BlendOp(src->opColor);
+ dst->opAlpha = QRhiGraphicsPipeline::BlendOp(src->opAlpha);
dst->colorWrite = QRhiGraphicsPipeline::ColorMask(int(src->colorWrite));
dst->cullMode = QRhiGraphicsPipeline::CullMode(src->cullMode);
dst->polygonMode = QRhiGraphicsPipeline::PolygonMode(src->polygonMode);
@@ -4141,6 +4149,8 @@ bool operator==(const GraphicsState &a, const GraphicsState &b) noexcept
&& a.dstColor == b.dstColor
&& a.srcAlpha == b.srcAlpha
&& a.dstAlpha == b.dstAlpha
+ && a.opColor == b.opColor
+ && a.opAlpha == b.opAlpha
&& a.colorWrite == b.colorWrite
&& a.cullMode == b.cullMode
&& a.usesScissor == b.usesScissor
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index a84797a4c6..11cec6b99b 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -599,6 +599,8 @@ struct GraphicsState
QRhiGraphicsPipeline::BlendFactor dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
QRhiGraphicsPipeline::BlendFactor srcAlpha = QRhiGraphicsPipeline::One;
QRhiGraphicsPipeline::BlendFactor dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
+ QRhiGraphicsPipeline::BlendOp opColor = QRhiGraphicsPipeline::Add;
+ QRhiGraphicsPipeline::BlendOp opAlpha = QRhiGraphicsPipeline::Add;
QRhiGraphicsPipeline::ColorMask colorWrite = QRhiGraphicsPipeline::ColorMask(0xF);
QRhiGraphicsPipeline::CullMode cullMode = QRhiGraphicsPipeline::None;
bool usesScissor = false;
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index 49508c1c35..c507f2a87f 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -6,8 +6,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQsgLeak)
-
#ifndef QT_NO_DEBUG
bool qsg_material_failure = false;
bool qsg_test_and_clear_material_failure()
@@ -414,10 +412,11 @@ int QSGMaterial::compare(const QSGMaterial *other) const
See \l QRhi::MultiView, \l QRhiColorAttachment::setMultiViewCount(), and
\l QRhiGraphicsPipeline::setMultiViewCount() for further, lower-level details
on multiview support in Qt. The Qt Quick scene graph renderer is prepared to
- recognize multiview render targets, when specified via
- \l QQuickRenderTarget::fromRhiRenderTarget() or the \c MultiView
- functions such as \l{QQuickRenderTarget::}{fromVulkanImageMultiView()}, and
- propagate the view count to graphics pipelines and the materials.
+ recognize multiview render targets, when specified via \l
+ QQuickRenderTarget::fromRhiRenderTarget() or the 3D API specific functions,
+ such as \l{QQuickRenderTarget::}{fromVulkanImage()} with an \c arraySize
+ argument greater than 1. The renderer will then propagate the view count to
+ graphics pipelines and the materials.
\since 6.8
*/
diff --git a/src/quick/scenegraph/coreapi/qsgmaterialshader.cpp b/src/quick/scenegraph/coreapi/qsgmaterialshader.cpp
index a661e47765..57090f73b3 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterialshader.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterialshader.cpp
@@ -661,6 +661,17 @@ bool QSGMaterialShader::updateGraphicsPipelineState(RenderState &state, Graphics
*/
/*!
+ \enum QSGMaterialShader::GraphicsPipelineState::BlendOp
+ \since 6.8
+
+ \value BlendOpAdd
+ \value BlendOpSubtract
+ \value BlendOpReverseSubtract
+ \value BlendOpMin
+ \value BlendOpMax
+ */
+
+/*!
\enum QSGMaterialShader::GraphicsPipelineState::ColorMaskComponent
\since 5.14
@@ -772,6 +783,18 @@ bool QSGMaterialShader::updateGraphicsPipelineState(RenderState &state, Graphics
*/
/*!
+ \variable QSGMaterialShader::GraphicsPipelineState::opColor
+ \since 6.8
+ \brief RGB blending operation.
+ */
+
+/*!
+ \variable QSGMaterialShader::GraphicsPipelineState::opAlpha
+ \since 6.8
+ \brief Alpha blending operation.
+ */
+
+/*!
Returns the accumulated opacity to be used for rendering.
*/
float QSGMaterialShader::RenderState::opacity() const
diff --git a/src/quick/scenegraph/coreapi/qsgmaterialshader.h b/src/quick/scenegraph/coreapi/qsgmaterialshader.h
index 795da77477..85ebf6eb8a 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterialshader.h
+++ b/src/quick/scenegraph/coreapi/qsgmaterialshader.h
@@ -83,6 +83,14 @@ public:
OneMinusSrc1Alpha
};
+ enum BlendOp {
+ BlendOpAdd,
+ BlendOpSubtract,
+ BlendOpReverseSubtract,
+ BlendOpMin,
+ BlendOpMax
+ };
+
enum ColorMaskComponent {
R = 1 << 0,
G = 1 << 1,
@@ -112,6 +120,9 @@ public:
bool separateBlendFactors;
BlendFactor srcAlpha;
BlendFactor dstAlpha;
+ BlendOp opColor;
+ BlendOp opAlpha;
+
// This struct is extensible while keeping BC since apps only ever get
// a ptr to the struct, it is not created by them.
};
diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
index b77f33d6a3..ca1b8fc2e9 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -11,8 +11,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQsgLeak)
-
#ifndef QT_NO_DEBUG
static int qt_node_count = 0;
diff --git a/src/quick/scenegraph/coreapi/qsgtexture.cpp b/src/quick/scenegraph/coreapi/qsgtexture.cpp
index 57111e9e5f..c08f900f55 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture.cpp
+++ b/src/quick/scenegraph/coreapi/qsgtexture.cpp
@@ -15,7 +15,7 @@
#define CAN_BACKTRACE_EXECINFO
#endif
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_APPLE)
#define CAN_BACKTRACE_EXECINFO
#endif
@@ -35,8 +35,6 @@ Q_GLOBAL_STATIC(QMutex, qsg_valid_texture_mutex)
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQsgLeak)
-
bool operator==(const QSGSamplerDescription &a, const QSGSamplerDescription &b) noexcept
{
return a.filtering == b.filtering
@@ -103,7 +101,7 @@ QSGTexturePrivate::QSGTexturePrivate(QSGTexture *t)
static int qt_debug_texture_count = 0;
-#if (defined(Q_OS_LINUX) || defined (Q_OS_MAC)) && !defined(Q_OS_ANDROID)
+#if (defined(Q_OS_LINUX) || defined (Q_OS_APPLE)) && !defined(Q_OS_ANDROID)
DEFINE_BOOL_CONFIG_OPTION(qmlDebugLeakBacktrace, QML_DEBUG_LEAK_BACKTRACE)
#define BACKTRACE_SIZE 20
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index 9ce21d6b8f..b62919c2e9 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -166,7 +166,12 @@ void QSGDistanceFieldGlyphCache::update()
distanceFields.reserve(pendingGlyphsSize);
for (int i = 0; i < pendingGlyphsSize; ++i) {
GlyphData &gd = glyphData(m_pendingGlyphs.at(i));
- distanceFields.append(QDistanceField(gd.path,
+
+ QSize size = QSize(qCeil(gd.texCoord.width + gd.texCoord.xMargin * 2),
+ qCeil(gd.texCoord.height + gd.texCoord.yMargin * 2));
+
+ distanceFields.append(QDistanceField(size,
+ gd.path,
m_pendingGlyphs.at(i),
m_doubleGlyphResolution));
gd.path = QPainterPath(); // no longer needed, so release memory used by the painter path
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index 885b207f40..fc2e6ef1ad 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -34,6 +34,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQsgLeak)
+
class QSGContextPrivate;
class QSGInternalRectangleNode;
class QSGInternalImageNode;
diff --git a/src/quick/scenegraph/qsgcontextplugin.cpp b/src/quick/scenegraph/qsgcontextplugin.cpp
index 8026f68eb4..9dbf263765 100644
--- a/src/quick/scenegraph/qsgcontextplugin.cpp
+++ b/src/quick/scenegraph/qsgcontextplugin.cpp
@@ -16,8 +16,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_INFO)
-
QSGContextPlugin::QSGContextPlugin(QObject *parent)
: QObject(parent)
{
diff --git a/src/quick/scenegraph/qsgcurvefillnode.cpp b/src/quick/scenegraph/qsgcurvefillnode.cpp
index 9fa526bb0a..0a4a42341e 100644
--- a/src/quick/scenegraph/qsgcurvefillnode.cpp
+++ b/src/quick/scenegraph/qsgcurvefillnode.cpp
@@ -9,6 +9,7 @@ QT_BEGIN_NAMESPACE
QSGCurveFillNode::QSGCurveFillNode()
{
setFlag(OwnsGeometry, true);
+ setFlag(UsePreprocess, true);
setGeometry(new QSGGeometry(attributes(), 0, 0));
updateMaterial();
diff --git a/src/quick/scenegraph/qsgcurvefillnode_p.cpp b/src/quick/scenegraph/qsgcurvefillnode_p.cpp
index 387f4b3ce6..331620cf94 100644
--- a/src/quick/scenegraph/qsgcurvefillnode_p.cpp
+++ b/src/quick/scenegraph/qsgcurvefillnode_p.cpp
@@ -6,6 +6,7 @@
#include "util/qsggradientcache_p.h"
#include <private/qsgtexture_p.h>
+#include <private/qsgplaintexture_p.h>
QT_BEGIN_NAMESPACE
@@ -15,6 +16,7 @@ namespace {
{
public:
QSGCurveFillMaterialShader(QGradient::Type gradientType,
+ bool useTextureFill,
bool useDerivatives,
int viewCount);
@@ -24,6 +26,7 @@ namespace {
};
QSGCurveFillMaterialShader::QSGCurveFillMaterialShader(QGradient::Type gradientType,
+ bool useTextureFill,
bool useDerivatives,
int viewCount)
{
@@ -35,6 +38,8 @@ namespace {
baseName += QStringLiteral("_rg");
} else if (gradientType == QGradient::ConicalGradient) {
baseName += QStringLiteral("_cg");
+ } else if (useTextureFill) {
+ baseName += QStringLiteral("_tf");
}
if (useDerivatives)
@@ -48,15 +53,50 @@ namespace {
QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
{
Q_UNUSED(oldMaterial);
- const QSGCurveFillMaterial *m = static_cast<QSGCurveFillMaterial *>(newMaterial);
+ QSGCurveFillMaterial *m = static_cast<QSGCurveFillMaterial *>(newMaterial);
const QSGCurveFillNode *node = m->node();
- if (binding != 1 || node->gradientType() == QGradient::NoGradient)
+ if (binding != 1
+ || (node->gradientType() == QGradient::NoGradient && node->fillTextureProvider() == nullptr)) {
return;
+ }
+
+ QSGTexture *t = nullptr;
+ if (node->gradientType() != QGradient::NoGradient) {
+ const QSGGradientCacheKey cacheKey(node->fillGradient()->stops,
+ node->fillGradient()->spread);
+ t = QSGGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
+ } else if (node->fillTextureProvider() != nullptr) {
+ t = node->fillTextureProvider()->texture();
+ if (t != nullptr && t->isAtlasTexture()) {
+ // Create a non-atlas copy to make texture coordinate wrapping work. This
+ // texture copy is owned by the QSGTexture so memory is managed with the original
+ // texture provider.
+ QSGTexture *newTexture = t->removedFromAtlas(state.resourceUpdateBatch());
+ if (newTexture != nullptr)
+ t = newTexture;
+ }
+
+ }
+
+ if (t != nullptr) {
+ t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+ } else {
+ if (m->dummyTexture() == nullptr) {
+ QSGPlainTexture *dummyTexture = new QSGPlainTexture;
+ dummyTexture->setFiltering(QSGTexture::Nearest);
+ dummyTexture->setHorizontalWrapMode(QSGTexture::Repeat);
+ dummyTexture->setVerticalWrapMode(QSGTexture::Repeat);
+ QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
+ img.fill(0);
+ dummyTexture->setImage(img);
+ dummyTexture->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+
+ m->setDummyTexture(dummyTexture);
+ }
+
+ t = m->dummyTexture();
+ }
- const QSGGradientCacheKey cacheKey(node->fillGradient()->stops,
- node->fillGradient()->spread);
- QSGTexture *t = QSGGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
- t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
*texture = t;
}
@@ -76,11 +116,11 @@ namespace {
}
matrixScale = qSqrt(qAbs(state.determinant()));
- memcpy(buf->data() + offset + matrixCount * 64, &matrixScale, 4);
+ memcpy(buf->data() + offset + newEffect->viewCount() * 64, &matrixScale, 4);
changed = true;
}
- offset += matrixCount * 64 + 4;
+ offset += newEffect->viewCount() * 64 + 4;
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
@@ -105,7 +145,8 @@ namespace {
}
offset += 8;
- if (newNode->gradientType() == QGradient::NoGradient) {
+ if (newNode->gradientType() == QGradient::NoGradient
+ && newNode->fillTextureProvider() == nullptr) {
Q_ASSERT(buf->size() >= offset + 16);
QVector4D newColor = QVector4D(newNode->color().redF(),
@@ -125,6 +166,36 @@ namespace {
}
offset += 16;
+ } else {
+ Q_ASSERT(buf->size() >= offset + 64);
+
+ if (!oldNode || *oldNode->fillTransform() != *newNode->fillTransform()) {
+ memcpy(buf->data() + offset, newNode->fillTransform()->invertedData(), 64);
+ changed = true;
+ }
+
+ offset += 64;
+ }
+
+ if (newNode->gradientType() == QGradient::NoGradient
+ && newNode->fillTextureProvider() != nullptr) {
+ Q_ASSERT(buf->size() >= offset + 8);
+ const QSizeF newTextureSize = newNode->fillTextureProvider()->texture() != nullptr
+ ? newNode->fillTextureProvider()->texture()->textureSize()
+ : QSizeF(0, 0);
+ const QVector2D newBoundsSize(newTextureSize.width() / state.devicePixelRatio(),
+ newTextureSize.height() / state.devicePixelRatio());
+ const QVector2D oldBoundsSize = oldNode != nullptr
+ ? oldNode->boundsSize()
+ : QVector2D{};
+
+ if (oldEffect == nullptr || newBoundsSize != oldBoundsSize) {
+ newNode->setBoundsSize(newBoundsSize);
+ memcpy(buf->data() + offset, &newBoundsSize, 8);
+ changed = true;
+ }
+ offset += 8;
+
} else if (newNode->gradientType() == QGradient::LinearGradient) {
Q_ASSERT(buf->size() >= offset + 8 + 8);
@@ -233,6 +304,11 @@ QSGCurveFillMaterial::QSGCurveFillMaterial(QSGCurveFillNode *node)
setFlag(RequiresDeterminant, true);
}
+QSGCurveFillMaterial::~QSGCurveFillMaterial()
+{
+ delete m_dummyTexture;
+}
+
int QSGCurveFillMaterial::compare(const QSGMaterial *other) const
{
if (other->type() != type())
@@ -246,7 +322,7 @@ int QSGCurveFillMaterial::compare(const QSGMaterial *other) const
if (a == b)
return 0;
- if (a->gradientType() == QGradient::NoGradient) {
+ if (a->gradientType() == QGradient::NoGradient && a->fillTextureProvider() == nullptr) {
if (int d = a->color().red() - b->color().red())
return d;
if (int d = a->color().green() - b->color().green())
@@ -256,52 +332,63 @@ int QSGCurveFillMaterial::compare(const QSGMaterial *other) const
if (int d = a->color().alpha() - b->color().alpha())
return d;
} else {
- const QSGGradientCache::GradientDesc &ga = *a->fillGradient();
- const QSGGradientCache::GradientDesc &gb = *b->fillGradient();
+ if (a->gradientType() != QGradient::NoGradient) {
+ const QSGGradientCache::GradientDesc &ga = *a->fillGradient();
+ const QSGGradientCache::GradientDesc &gb = *b->fillGradient();
- if (int d = ga.a.x() - gb.a.x())
- return d;
- if (int d = ga.a.y() - gb.a.y())
- return d;
- if (int d = ga.b.x() - gb.b.x())
- return d;
- if (int d = ga.b.y() - gb.b.y())
- return d;
-
- if (int d = ga.v0 - gb.v0)
- return d;
- if (int d = ga.v1 - gb.v1)
- return d;
-
- if (int d = ga.spread - gb.spread)
- return d;
+ if (int d = ga.a.x() - gb.a.x())
+ return d;
+ if (int d = ga.a.y() - gb.a.y())
+ return d;
+ if (int d = ga.b.x() - gb.b.x())
+ return d;
+ if (int d = ga.b.y() - gb.b.y())
+ return d;
- if (int d = ga.stops.size() - gb.stops.size())
- return d;
+ if (int d = ga.v0 - gb.v0)
+ return d;
+ if (int d = ga.v1 - gb.v1)
+ return d;
- for (int i = 0; i < ga.stops.size(); ++i) {
- if (int d = ga.stops[i].first - gb.stops[i].first)
+ if (int d = ga.spread - gb.spread)
return d;
- if (int d = ga.stops[i].second.rgba() - gb.stops[i].second.rgba())
+
+ if (int d = ga.stops.size() - gb.stops.size())
return d;
+
+ for (int i = 0; i < ga.stops.size(); ++i) {
+ if (int d = ga.stops[i].first - gb.stops[i].first)
+ return d;
+ if (int d = ga.stops[i].second.rgba() - gb.stops[i].second.rgba())
+ return d;
+ }
}
+
+ if (int d = a->fillTransform()->compareTo(*b->fillTransform()))
+ return d;
}
- return 0;
+ const qintptr diff = qintptr(a->fillTextureProvider()) - qintptr(b->fillTextureProvider());
+ return diff < 0 ? -1 : (diff > 0 ? 1 : 0);
}
QSGMaterialType *QSGCurveFillMaterial::type() const
{
- static QSGMaterialType type[4];
+ static QSGMaterialType type[5];
uint index = node()->gradientType();
Q_ASSERT((index & ~3) == 0); // Only two first bits for gradient type
+ if (node()->gradientType() == QGradient::NoGradient && node()->fillTextureProvider() != nullptr)
+ index = 5;
+
return &type[index];
}
QSGMaterialShader *QSGCurveFillMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
{
return new QSGCurveFillMaterialShader(node()->gradientType(),
+ node()->gradientType() == QGradient::NoGradient
+ && node()->fillTextureProvider() != nullptr,
renderMode == QSGRendererInterface::RenderMode3D,
viewCount());
}
diff --git a/src/quick/scenegraph/qsgcurvefillnode_p.h b/src/quick/scenegraph/qsgcurvefillnode_p.h
index c90c5b8d38..441576a814 100644
--- a/src/quick/scenegraph/qsgcurvefillnode_p.h
+++ b/src/quick/scenegraph/qsgcurvefillnode_p.h
@@ -8,7 +8,9 @@
#include <QtQuick/qtquickexports.h>
#include <QtQuick/private/qsggradientcache_p.h>
+#include <QtQuick/private/qsgtransform_p.h>
#include <QtQuick/qsgnode.h>
+#include <QtQuick/qsgtextureprovider.h>
#include "qsgcurveabstractnode_p.h"
@@ -25,17 +27,18 @@
QT_BEGIN_NAMESPACE
-class Q_QUICK_EXPORT QSGCurveFillNode : public QSGCurveAbstractNode
+class QSGTextureProvider;
+
+class Q_QUICK_EXPORT QSGCurveFillNode : public QObject, public QSGCurveAbstractNode
{
+ Q_OBJECT
public:
QSGCurveFillNode();
void setColor(QColor col) override
{
- if (m_color == col)
- return;
m_color = col;
- updateMaterial();
+ markDirty(DirtyMaterial);
}
QColor color() const
@@ -43,9 +46,39 @@ public:
return m_color;
}
+ void setFillTextureProvider(QSGTextureProvider *provider)
+ {
+ if (provider == m_textureProvider)
+ return;
+
+ if (m_textureProvider != nullptr) {
+ disconnect(m_textureProvider, &QSGTextureProvider::textureChanged,
+ this, &QSGCurveFillNode::handleTextureChanged);
+ disconnect(m_textureProvider, &QSGTextureProvider::destroyed,
+ this, &QSGCurveFillNode::handleTextureProviderDestroyed);
+ }
+
+ m_textureProvider = provider;
+ markDirty(DirtyMaterial);
+
+ if (m_textureProvider != nullptr) {
+ connect(m_textureProvider, &QSGTextureProvider::textureChanged,
+ this, &QSGCurveFillNode::handleTextureChanged);
+ connect(m_textureProvider, &QSGTextureProvider::destroyed,
+ this, &QSGCurveFillNode::handleTextureProviderDestroyed);
+ }
+ }
+
+
+ QSGTextureProvider *fillTextureProvider() const
+ {
+ return m_textureProvider;
+ }
+
void setFillGradient(const QSGGradientCache::GradientDesc &fillGradient)
{
m_fillGradient = fillGradient;
+ markDirty(DirtyMaterial);
}
const QSGGradientCache::GradientDesc *fillGradient() const
@@ -55,10 +88,8 @@ public:
void setGradientType(QGradient::Type type)
{
- if (m_gradientType != type) {
- m_gradientType = type;
- updateMaterial();
- }
+ m_gradientType = type;
+ markDirty(DirtyMaterial);
}
QGradient::Type gradientType() const
@@ -66,6 +97,17 @@ public:
return m_gradientType;
}
+ void setFillTransform(const QSGTransform &transform)
+ {
+ m_fillTransform = transform;
+ markDirty(DirtyMaterial);
+ }
+
+ const QSGTransform *fillTransform() const
+ {
+ return &m_fillTransform;
+ }
+
float debug() const
{
return m_debug;
@@ -171,6 +213,36 @@ public:
m_uncookedVertexes.reserve(size);
}
+ void preprocess() override
+ {
+ if (m_textureProvider != nullptr) {
+ if (QSGDynamicTexture *texture = qobject_cast<QSGDynamicTexture *>(m_textureProvider->texture()))
+ texture->updateTexture();
+ }
+ }
+
+ QVector2D boundsSize() const
+ {
+ return m_boundsSize;
+ }
+
+ void setBoundsSize(const QVector2D &boundsSize)
+ {
+ m_boundsSize = boundsSize;
+ }
+
+private Q_SLOTS:
+ void handleTextureChanged()
+ {
+ markDirty(DirtyMaterial);
+ }
+
+ void handleTextureProviderDestroyed()
+ {
+ m_textureProvider = nullptr;
+ markDirty(DirtyMaterial);
+ }
+
private:
struct CurveNodeVertex
{
@@ -182,15 +254,18 @@ private:
void updateMaterial();
static const QSGGeometry::AttributeSet &attributes();
- QColor m_color = Qt::white;
- float m_debug = 0.0f;
- QSGGradientCache::GradientDesc m_fillGradient;
- QGradient::Type m_gradientType = QGradient::NoGradient;
-
QScopedPointer<QSGMaterial> m_material;
QVector<CurveNodeVertex> m_uncookedVertexes;
QVector<quint32> m_uncookedIndexes;
+
+ QSGGradientCache::GradientDesc m_fillGradient;
+ QSGTextureProvider *m_textureProvider = nullptr;
+ QVector2D m_boundsSize;
+ QSGTransform m_fillTransform;
+ QColor m_color = Qt::white;
+ QGradient::Type m_gradientType = QGradient::NoGradient;
+ float m_debug = 0.0f;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgcurvefillnode_p_p.h b/src/quick/scenegraph/qsgcurvefillnode_p_p.h
index f2a6535c6f..9cc80f3dca 100644
--- a/src/quick/scenegraph/qsgcurvefillnode_p_p.h
+++ b/src/quick/scenegraph/qsgcurvefillnode_p_p.h
@@ -21,10 +21,12 @@
QT_BEGIN_NAMESPACE
class QSGCurveFillNode;
+class QSGPlainTexture;
class Q_QUICK_EXPORT QSGCurveFillMaterial : public QSGMaterial
{
public:
QSGCurveFillMaterial(QSGCurveFillNode *node);
+ ~QSGCurveFillMaterial() override;
int compare(const QSGMaterial *other) const override;
QSGCurveFillNode *node() const
@@ -32,11 +34,22 @@ public:
return m_node;
}
+ QSGPlainTexture *dummyTexture() const
+ {
+ return m_dummyTexture;
+ }
+
+ void setDummyTexture(QSGPlainTexture *dummyTexture)
+ {
+ m_dummyTexture = dummyTexture;
+ }
+
private:
QSGMaterialType *type() const override;
QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override;
QSGCurveFillNode *m_node;
+ QSGPlainTexture *m_dummyTexture = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgcurveprocessor.cpp b/src/quick/scenegraph/qsgcurveprocessor.cpp
index f2e95d691c..b647b9ffdf 100644
--- a/src/quick/scenegraph/qsgcurveprocessor.cpp
+++ b/src/quick/scenegraph/qsgcurveprocessor.cpp
@@ -10,7 +10,7 @@
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcSGCurveProcessor, "qt.quick.curveprocessor");
-Q_LOGGING_CATEGORY(lcSGCurveIntersectionSolver, "qt.quick.curveprocessor.intersections");
+Q_STATIC_LOGGING_CATEGORY(lcSGCurveIntersectionSolver, "qt.quick.curveprocessor.intersections");
namespace {
// Input coordinate space is pre-mapped so that (0, 0) maps to [0, 0] in uv space.
@@ -1379,7 +1379,7 @@ bool QSGCurveProcessor::solveIntersections(QQuadPath &path, bool removeNestedPat
// For winding fill we take the left most path forward, so the inside stays on the right side
// For odd even fill we take the right most path forward so we cut of the smallest area.
// We come back at the intersection and add the missing pieces as subpaths later on.
- if (t2 != 0 && t2 != 1) {
+ if (t1 !=0 && t1 != 1 && t2 != 0 && t2 != 1) {
QVector2D tangent1 = elem1.tangentAtFraction(t1);
if (!forward)
tangent1 = -tangent1;
diff --git a/src/quick/scenegraph/qsgcurveprocessor_p.h b/src/quick/scenegraph/qsgcurveprocessor_p.h
index cdd93bc58e..69f3a3a661 100644
--- a/src/quick/scenegraph/qsgcurveprocessor_p.h
+++ b/src/quick/scenegraph/qsgcurveprocessor_p.h
@@ -18,8 +18,12 @@
#include <QtQuick/qtquickexports.h>
#include "util/qquadpath_p.h"
+#include <QtCore/qloggingcategory.h>
+
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcSGCurveProcessor);
+
class Q_QUICK_EXPORT QSGCurveProcessor
{
public:
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
index d92bf0a836..4c75c2239f 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
@@ -22,6 +22,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcSgText)
+
class QSGRenderContext;
class QSGDistanceFieldTextMaterial;
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 84450c692b..8b4afea707 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -7,7 +7,7 @@
#include <QtCore/QWaitCondition>
#include <QtCore/QAnimationDriver>
#include <QtCore/QQueue>
-#include <QtCore/QTime>
+#include <QtCore/QTimer>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
@@ -18,6 +18,7 @@
#include <QtQuick/QQuickWindow>
#include <private/qquickwindow_p.h>
#include <private/qquickitem_p.h>
+#include <QtGui/qpa/qplatformwindow_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
@@ -1461,10 +1462,29 @@ void QSGThreadedRenderLoop::update(QQuickWindow *window)
if (!w)
return;
- if (w->thread == QThread::currentThread()) {
- qCDebug(QSG_LOG_RENDERLOOP) << "update on window - on render thread" << w->window;
- w->thread->requestRepaint();
- return;
+ const bool isRenderThread = QThread::currentThread() == w->thread;
+
+#if defined(Q_OS_MACOS)
+ using namespace QNativeInterface::Private;
+ if (auto *cocoaWindow = dynamic_cast<QCocoaWindow*>(window->handle())) {
+ // If the window is being resized we don't want to schedule unthrottled
+ // updates on the render thread, as this will starve the main thread
+ // from getting drawables for displaying the updated window size.
+ if (isRenderThread && cocoaWindow->inLiveResize()) {
+ // In most cases the window will already have update requested
+ // due to the animator triggering a sync, but just in case we
+ // schedule an update request on the main thread explicitly.
+ qCDebug(QSG_LOG_RENDERLOOP) << "window is resizing. update on window" << w->window;
+ QTimer::singleShot(0, window, [=]{ window->requestUpdate(); });
+ return;
+ }
+ }
+#endif
+
+ if (isRenderThread) {
+ qCDebug(QSG_LOG_RENDERLOOP) << "update on window - on render thread" << w->window;
+ w->thread->requestRepaint();
+ return;
}
qCDebug(QSG_LOG_RENDERLOOP) << "update on window" << w->window;
diff --git a/src/quick/scenegraph/shaders_ng/shapecurve.frag b/src/quick/scenegraph/shaders_ng/shapecurve.frag
index bd0d02b73b..cc97f375ab 100644
--- a/src/quick/scenegraph/shaders_ng/shapecurve.frag
+++ b/src/quick/scenegraph/shaders_ng/shapecurve.frag
@@ -10,9 +10,10 @@ layout(location = 1) in vec4 gradient;
layout(location = 2) in float gradTabIndex;
#elif defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
layout(location = 2) in vec2 coord;
+#elif defined(TEXTUREFILL)
+layout(location = 2) in vec2 textureCoord;
#endif
-
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
@@ -26,6 +27,9 @@ layout(std140, binding = 0) uniform buf {
float debug;
float reserved3;
+#if defined(LINEARGRADIENT) || defined(RADIALGRADIENT) || defined(CONICALGRADIENT) || defined(TEXTUREFILL)
+ mat4 gradientMatrix;
+#endif
#if defined(LINEARGRADIENT)
vec2 gradientStart;
vec2 gradientEnd;
@@ -37,6 +41,8 @@ layout(std140, binding = 0) uniform buf {
#elif defined(CONICALGRADIENT)
vec2 translationPoint;
float angle;
+#elif defined(TEXTUREFILL)
+ vec2 boundsSize;
#else
vec4 color;
#endif
@@ -46,6 +52,8 @@ layout(std140, binding = 0) uniform buf {
#if defined(LINEARGRADIENT) || defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
layout(binding = 1) uniform sampler2D gradTabTexture;
+#elif defined(TEXTUREFILL)
+layout(binding = 1) uniform sampler2D sourceTexture;
#endif
vec4 baseColor()
@@ -74,6 +82,8 @@ vec4 baseColor()
else
t = (atan(-coord.y, coord.x) + ubuf.angle) * INVERSE_2PI;
return texture(gradTabTexture, vec2(t - floor(t), 0.5));
+#elif defined(TEXTUREFILL)
+ return texture(sourceTexture, textureCoord);
#else
return vec4(ubuf.color.rgb, 1.0) * ubuf.color.a;
#endif
diff --git a/src/quick/scenegraph/shaders_ng/shapecurve.vert b/src/quick/scenegraph/shaders_ng/shapecurve.vert
index 688aa83139..3ff53978b8 100644
--- a/src/quick/scenegraph/shaders_ng/shapecurve.vert
+++ b/src/quick/scenegraph/shaders_ng/shapecurve.vert
@@ -12,6 +12,8 @@ layout(location = 1) out vec4 gradient;
layout(location = 2) out float gradTabIndex;
#elif defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
layout(location = 2) out vec2 coord;
+#elif defined(TEXTUREFILL)
+layout(location = 2) out vec2 textureCoord;
#endif
layout(std140, binding = 0) uniform buf {
@@ -25,6 +27,9 @@ layout(std140, binding = 0) uniform buf {
float debug;
float reserved3;
+#if defined(LINEARGRADIENT) || defined(RADIALGRADIENT) || defined(CONICALGRADIENT) || defined(TEXTUREFILL)
+ mat4 gradientMatrix;
+#endif
#if defined(LINEARGRADIENT)
vec2 gradientStart;
vec2 gradientEnd;
@@ -36,6 +41,8 @@ layout(std140, binding = 0) uniform buf {
#elif defined(CONICALGRADIENT)
vec2 translationPoint;
float angle;
+#elif defined(TEXTUREFILL)
+ vec2 boundsSize;
#else
vec4 color;
#endif
@@ -64,11 +71,17 @@ void main()
gradient = vertexGradient / ubuf.matrixScale;
+#if defined(LINEARGRADIENT) || defined(RADIALGRADIENT) || defined(CONICALGRADIENT) || defined(TEXTUREFILL)
+ vec2 gradVertexCoord = (ubuf.gradientMatrix * vertexCoord).xy;
+#endif
#if defined(LINEARGRADIENT)
vec2 gradVec = ubuf.gradientEnd - ubuf.gradientStart;
- gradTabIndex = dot(gradVec, vertexCoord.xy - ubuf.gradientStart.xy) / dot(gradVec, gradVec);
+ gradTabIndex = dot(gradVec, gradVertexCoord - ubuf.gradientStart) / dot(gradVec, gradVec);
#elif defined(RADIALGRADIENT) || defined(CONICALGRADIENT)
- coord = vertexCoord.xy - ubuf.translationPoint;
+ coord = gradVertexCoord - ubuf.translationPoint;
+#elif defined(TEXTUREFILL)
+ textureCoord = vec2(gradVertexCoord.x / ubuf.boundsSize.x,
+ gradVertexCoord.y / ubuf.boundsSize.y);
#endif
#if QSHADER_VIEW_COUNT >= 2
diff --git a/src/quick/scenegraph/util/qquadpath.cpp b/src/quick/scenegraph/util/qquadpath.cpp
index 9b5cbcb0ae..457b864d5c 100644
--- a/src/quick/scenegraph/util/qquadpath.cpp
+++ b/src/quick/scenegraph/util/qquadpath.cpp
@@ -2,6 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquadpath_p.h"
+
+#include <private/qsgcurveprocessor_p.h>
+
#include <QtGui/private/qbezier_p.h>
#include <QtMath>
#include <QtCore/QLoggingCategory>
@@ -9,8 +12,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcSGCurveProcessor);
-
static qreal qt_scoreQuadratic(const QBezier &b, QPointF qcp)
{
static bool init = false;
diff --git a/src/quick/scenegraph/util/qsgtransform.cpp b/src/quick/scenegraph/util/qsgtransform.cpp
new file mode 100644
index 0000000000..7efb014c33
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgtransform.cpp
@@ -0,0 +1,10 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsgtransform_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QMatrix4x4 QSGTransform::m_identity;
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgtransform_p.h b/src/quick/scenegraph/util/qsgtransform_p.h
new file mode 100644
index 0000000000..f19d7a0efd
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgtransform_p.h
@@ -0,0 +1,105 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSGTRANSFORM_P_H
+#define QSGTRANSFORM_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of a number of Qt sources files. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QSharedPointer>
+#include <QMatrix4x4>
+#include <QtQuick/qtquickexports.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_EXPORT QSGTransform
+{
+public:
+ void setMatrix(const QMatrix4x4 &matrix)
+ {
+ if (matrix.isIdentity())
+ m_matrixPtr.clear();
+ else
+ m_matrixPtr = QSharedPointer<QMatrix4x4>::create(matrix);
+ m_invertedPtr.clear();
+ }
+
+ QMatrix4x4 matrix() const
+ {
+ return m_matrixPtr ? *m_matrixPtr : m_identity;
+ }
+
+ bool isIdentity() const
+ {
+ return !m_matrixPtr;
+ }
+
+ bool operator==(const QMatrix4x4 &other) const
+ {
+ return m_matrixPtr ? (other == *m_matrixPtr) : other.isIdentity();
+ }
+
+ bool operator!=(const QMatrix4x4 &other) const
+ {
+ return !(*this == other);
+ }
+
+ bool operator==(const QSGTransform &other) const
+ {
+ return (m_matrixPtr == other.m_matrixPtr)
+ || (m_matrixPtr && other.m_matrixPtr && *m_matrixPtr == *other.m_matrixPtr);
+ }
+
+ bool operator!=(const QSGTransform &other) const
+ {
+ return !(*this == other);
+ }
+
+ int compareTo(const QSGTransform &other) const
+ {
+ int diff = 0;
+ if (m_matrixPtr != other.m_matrixPtr) {
+ if (m_matrixPtr.isNull()) {
+ diff = -1;
+ } else if (other.m_matrixPtr.isNull()) {
+ diff = 1;
+ } else {
+ const float *ptr1 = m_matrixPtr->constData();
+ const float *ptr2 = other.m_matrixPtr->constData();
+ for (int i = 0; i < 16 && !diff; i++) {
+ float d = ptr1[i] - ptr2[i];
+ if (d != 0)
+ diff = (d > 0) ? 1 : -1;
+ }
+ }
+ }
+ return diff;
+ }
+
+ const float *invertedData() const
+ {
+ if (!m_matrixPtr)
+ return m_identity.constData();
+ if (!m_invertedPtr)
+ m_invertedPtr = QSharedPointer<QMatrix4x4>::create(m_matrixPtr->inverted());
+ return m_invertedPtr->constData();
+ }
+
+private:
+ static QMatrix4x4 m_identity;
+ QSharedPointer<QMatrix4x4> m_matrixPtr;
+ mutable QSharedPointer<QMatrix4x4> m_invertedPtr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGTRANSFORM_P_H
diff --git a/src/quick/util/qminimalflatset_p.h b/src/quick/util/qminimalflatset_p.h
deleted file mode 100644
index 0a882205ef..0000000000
--- a/src/quick/util/qminimalflatset_p.h
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QTDECLARATIVE_QMINIMALFLATSET_P_H
-#define QTDECLARATIVE_QMINIMALFLATSET_P_H
-
-#if __has_include(<QtCore/private/qminimalflatset_p.h>)
-# include <QtCore/private/qminimalflatset_p.h>
-#else
-
-//
-// 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 <QtQuick/qtquickglobal.h>
-
-#include <QtCore/qcontainerfwd.h>
-#include <QtCore/private/qglobal_p.h>
-
-//#define QMINIMAL_FLAT_SET_DEBUG
-#ifdef QMINIMAL_FLAT_SET_DEBUG
-# include <QtCore/qscopeguard.h>
-# include <QtCore/qdebug.h>
-# define QMINIMAL_FLAT_SET_PRINT_AT_END \
- const auto sg = qScopeGuard([&] { qDebug() << this << *this; });
-#else
-# define QMINIMAL_FLAT_SET_PRINT_AT_END
-#endif
-
-#include <algorithm> // for std::lower_bound
-
-QT_BEGIN_NAMESPACE
-
-/*
- This is a minimal version of a QFlatSet, the std::set version of QFlatMap.
- Like QFlatMap, it has linear insertion and removal, not logarithmic, like
- real QMap and std::set, so it's only a good container if you either have
- very few entries or lots, but with separate setup and lookup stages.
- Because a full QFlatSet would be 10x the work on writing this minimal one,
- we keep it here for now. When more users pop up and the class has matured a
- bit, we can consider moving it alongside QFlatMap in QtCore.
-*/
-
-template <typename T, typename Container = QList<T>>
-class QMinimalFlatSet
-{
- Container c;
-public:
- // compiler-generated default ctor is ok!
- // compiler-generated copy/move ctor/assignment operators are ok!
- // compiler-generated dtor is ok!
-
- using const_iterator = typename Container::const_iterator;
- using iterator = const_iterator;
- using const_reverse_iterator = typename Container::const_reverse_iterator;
- using reverse_iterator = const_reverse_iterator;
- using value_type = T;
-
- iterator begin() const { return c.cbegin(); }
- iterator end() const { return c.cend(); }
- iterator cbegin() const { return begin(); }
- iterator cend() const { return cend(); }
-
- reverse_iterator rbegin() const { return c.crbegin(); }
- reverse_iterator rend() const { return c.crend(); }
- reverse_iterator crbegin() const { return rbegin(); }
- reverse_iterator crend() const { return rend(); }
-
- void clear() {
- QMINIMAL_FLAT_SET_PRINT_AT_END
- c.clear();
- }
- auto size() const { return c.size(); }
- auto count() const { return size(); }
- bool isEmpty() const { return size() == 0; }
-
- std::pair<iterator, bool> insert(value_type &&v)
- {
- QMINIMAL_FLAT_SET_PRINT_AT_END
- const auto r = lookup(v);
- if (r.exists)
- return {r.it, false};
- else
- return {c.insert(r.it, std::move(v)), true};
- }
-
- std::pair<iterator, bool> insert(const value_type &v)
- {
- QMINIMAL_FLAT_SET_PRINT_AT_END
- const auto r = lookup(v);
- if (r.exists)
- return {r.it, false};
- else
- return {c.insert(r.it, v), true};
- }
-
- void erase(const value_type &v)
- {
- QMINIMAL_FLAT_SET_PRINT_AT_END
- const auto r = lookup(v);
- if (r.exists)
- c.erase(r.it);
- }
- void remove(const value_type &v) { erase(v); }
-
- bool contains(const value_type &v) const
- {
- return lookup(v).exists;
- }
-
- const Container &values() const & { return c; }
- Container values() && { return std::move(c); }
-
-private:
- auto lookup(const value_type &v) const
- {
- struct R {
- iterator it;
- bool exists;
- };
-
- const auto it = std::lower_bound(c.cbegin(), c.cend(), v);
- return R{it, it != c.cend() && !(v < *it)};
- }
-
-#ifdef QMINIMAL_FLAT_SET_DEBUG
- friend QDebug operator<<(QDebug dbg, const QMinimalFlatSet &set)
- {
- const QDebugStateSaver saver(dbg);
- dbg.nospace() << "QMinimalFlatSet{";
- for (auto &e : set)
- dbg << e << ", ";
- return dbg << "}";
- }
-#endif
-};
-
-QT_END_NAMESPACE
-
-#endif // !__has_include(<QtCore/private/qminimalflatset_p.h>)
-
-#endif // QTDECLARATIVE_QMINIMALFLATSET_P_H
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index 12208f375d..2f3bc66013 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -290,6 +290,11 @@ void QQuickAbstractAnimation::setRunning(bool r)
// Therefore, the state of d->running will in that case be different than r if we are back in
// the root stack frame of the recursive calls to setRunning()
emit runningChanged(d->running);
+ } else if (d->animationInstance) {
+ // If there was a recursive call, make sure the d->running is set correctly
+ d->running = d->animationInstance->isRunning();
+ } else {
+ d->running = r;
}
}
diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp
index 34032d4801..1b2a888a22 100644
--- a/src/quick/util/qquickdeliveryagent.cpp
+++ b/src/quick/util/qquickdeliveryagent.cpp
@@ -25,16 +25,14 @@
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcTouch, "qt.quick.touch")
-Q_LOGGING_CATEGORY(lcTouchCmprs, "qt.quick.touch.compression")
+Q_STATIC_LOGGING_CATEGORY(lcTouchCmprs, "qt.quick.touch.compression")
Q_LOGGING_CATEGORY(lcTouchTarget, "qt.quick.touch.target")
Q_LOGGING_CATEGORY(lcMouse, "qt.quick.mouse")
-Q_LOGGING_CATEGORY(lcMouseTarget, "qt.quick.mouse.target")
-Q_LOGGING_CATEGORY(lcTablet, "qt.quick.tablet")
+Q_STATIC_LOGGING_CATEGORY(lcMouseTarget, "qt.quick.mouse.target")
+Q_STATIC_LOGGING_CATEGORY(lcTablet, "qt.quick.tablet")
Q_LOGGING_CATEGORY(lcPtr, "qt.quick.pointer")
-Q_LOGGING_CATEGORY(lcPtrLoc, "qt.quick.pointer.localization")
-Q_LOGGING_CATEGORY(lcPtrGrab, "qt.quick.pointer.grab")
-Q_LOGGING_CATEGORY(lcWheelTarget, "qt.quick.wheel.target")
-Q_LOGGING_CATEGORY(lcGestureTarget, "qt.quick.gesture.target")
+Q_STATIC_LOGGING_CATEGORY(lcPtrLoc, "qt.quick.pointer.localization")
+Q_STATIC_LOGGING_CATEGORY(lcWheelTarget, "qt.quick.wheel.target")
Q_LOGGING_CATEGORY(lcHoverTrace, "qt.quick.hover.trace")
Q_LOGGING_CATEGORY(lcFocus, "qt.quick.focus")
@@ -295,6 +293,41 @@ void QQuickDeliveryAgentPrivate::removeGrabber(QQuickItem *grabber, bool mouse,
}
}
+/*!
+ \internal
+
+ Clears all exclusive and passive grabs for the points in \a pointerEvent.
+
+ We never allow any kind of grab to persist after release, unless we're waiting
+ for a synth event from QtGui (as with most tablet events), so for points that
+ are fully released, the grab is cleared.
+
+ Called when QQuickWindow::event dispatches events, or when the QQuickOverlay
+ has filtered an event so that it bypasses normal delivery.
+*/
+void QQuickDeliveryAgentPrivate::clearGrabbers(QPointerEvent *pointerEvent)
+{
+ if (pointerEvent->isEndEvent()
+ && !(isTabletEvent(pointerEvent)
+ && (qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)
+ || QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse))) {
+ if (pointerEvent->isSinglePointEvent()) {
+ if (static_cast<QSinglePointEvent *>(pointerEvent)->buttons() == Qt::NoButton) {
+ auto &firstPt = pointerEvent->point(0);
+ pointerEvent->setExclusiveGrabber(firstPt, nullptr);
+ pointerEvent->clearPassiveGrabbers(firstPt);
+ }
+ } else {
+ for (auto &point : pointerEvent->points()) {
+ if (point.state() == QEventPoint::State::Released) {
+ pointerEvent->setExclusiveGrabber(point, nullptr);
+ pointerEvent->clearPassiveGrabbers(point);
+ }
+ }
+ }
+ }
+}
+
/*! \internal
Translates QEventPoint::scenePosition() in \a touchEvent to this window.
@@ -428,7 +461,7 @@ void QQuickDeliveryAgentPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *
}
}
- if (newActiveFocusItem && rootItem->hasFocus()) {
+ if (newActiveFocusItem && (rootItem->hasFocus() || (rootItem->window()->type() == Qt::Popup))) {
activeFocusItem = newActiveFocusItem;
QQuickItemPrivate::get(newActiveFocusItem)->activeFocus = true;
@@ -1788,14 +1821,11 @@ void QQuickDeliveryAgentPrivate::onGrabChanged(QObject *grabber, QPointingDevice
const bool grabGained = (transition == QPointingDevice::GrabTransition::GrabExclusive ||
transition == QPointingDevice::GrabTransition::GrabPassive);
- QQuickDeliveryAgent *deliveryAgent = nullptr;
-
// note: event can be null, if the signal was emitted from QPointingDevicePrivate::removeGrabber(grabber)
if (auto *handler = qmlobject_cast<QQuickPointerHandler *>(grabber)) {
if (handler->parentItem()) {
auto itemPriv = QQuickItemPrivate::get(handler->parentItem());
- deliveryAgent = itemPriv->deliveryAgent();
- if (deliveryAgent == q) {
+ if (itemPriv->deliveryAgent() == q) {
handler->onGrabChanged(handler, transition, const_cast<QPointerEvent *>(event),
const_cast<QEventPoint &>(point));
}
@@ -1841,7 +1871,6 @@ void QQuickDeliveryAgentPrivate::onGrabChanged(QObject *grabber, QPointingDevice
break;
}
auto *itemPriv = QQuickItemPrivate::get(grabberItem);
- deliveryAgent = itemPriv->deliveryAgent();
// An item that is NOT a subscene root needs to track whether it got a grab via a subscene delivery agent,
// whereas the subscene root item already knows it has its own DA.
if (isSubsceneAgent && grabGained && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
diff --git a/src/quick/util/qquickdeliveryagent_p.h b/src/quick/util/qquickdeliveryagent_p.h
index 0f42f4fa77..df195f16d0 100644
--- a/src/quick/util/qquickdeliveryagent_p.h
+++ b/src/quick/util/qquickdeliveryagent_p.h
@@ -25,6 +25,10 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcPtr)
+Q_DECLARE_LOGGING_CATEGORY(lcHoverTrace)
+Q_DECLARE_LOGGING_CATEGORY(lcTouchTarget)
+
class QQuickItem;
class QQuickDeliveryAgentPrivate;
diff --git a/src/quick/util/qquickdeliveryagent_p_p.h b/src/quick/util/qquickdeliveryagent_p_p.h
index 5678afb9f7..878561bc12 100644
--- a/src/quick/util/qquickdeliveryagent_p_p.h
+++ b/src/quick/util/qquickdeliveryagent_p_p.h
@@ -120,6 +120,7 @@ public:
bool deliverTouchAsMouse(QQuickItem *item, QTouchEvent *pointerEvent);
void translateTouchEvent(QTouchEvent *touchEvent);
void removeGrabber(QQuickItem *grabber, bool mouse = true, bool touch = true, bool cancel = false);
+ void clearGrabbers(QPointerEvent *pointerEvent);
void onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition, const QPointerEvent *event, const QEventPoint &point);
static QPointerEvent *clonePointerEvent(QPointerEvent *event, std::optional<QPointF> transformedLocalPos = std::nullopt);
void deliverToPassiveGrabbers(const QVector<QPointer<QObject> > &passiveGrabbers, QPointerEvent *pointerEvent);
diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp
index 8995c64d0b..bd90bf81b6 100644
--- a/src/quick/util/qquickpath.cpp
+++ b/src/quick/util/qquickpath.cpp
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE
be instantiated.
\sa Path, PathAttribute, PathPercent, PathLine, PathPolyline, PathQuad, PathCubic, PathArc,
- PathAngleArc, PathCurve, PathSvg
+ PathAngleArc, PathCurve, PathSvg, PathRectangle
*/
/*!
@@ -70,7 +70,7 @@ QT_BEGIN_NAMESPACE
\li Yes
\li Yes
\row
- \li PathMultiLine
+ \li PathMultiline
\li Yes
\li Yes
\li Yes
@@ -100,6 +100,11 @@ QT_BEGIN_NAMESPACE
\li Yes
\li Yes
\row
+ \li PathRectangle
+ \li Yes
+ \li Yes
+ \li Yes
+ \row
\li PathAttribute
\li Yes
\li N/A
@@ -119,7 +124,7 @@ QT_BEGIN_NAMESPACE
\note Path is a non-visual type; it does not display anything on its own.
To draw a path, use \l Shape.
- \sa PathView, Shape, PathAttribute, PathPercent, PathLine, PathPolyline, PathMove, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg
+ \sa PathView, Shape, PathAttribute, PathPercent, PathLine, PathPolyline, PathMove, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg, PathRectangle
*/
QQuickPath::QQuickPath(QObject *parent)
: QObject(*(new QQuickPathPrivate), parent)
@@ -210,6 +215,7 @@ bool QQuickPath::isClosed() const
\li \l PathArc - an arc to a given position with a radius.
\li \l PathAngleArc - an arc specified by center point, radii, and angles.
\li \l PathSvg - a path specified as an SVG path data string.
+ \li \l PathRectangle - a rectangle with a given position and size
\li \l PathCurve - a point on a Catmull-Rom curve.
\li \l PathAttribute - an attribute at a given position in the path.
\li \l PathPercent - a way to spread out items along various segments of the path.
@@ -284,6 +290,8 @@ void QQuickPath::pathElements_clear(QQmlListProperty<QQuickPathElement> *propert
d->_pathCurves.clear();
d->_pointCache.clear();
d->_pathTexts.clear();
+ d->_path.clear();
+ emit path->changed();
}
void QQuickPath::interpolate(int idx, const QString &name, qreal value)
@@ -1191,7 +1199,7 @@ void QQuickPathAttribute::setValue(qreal value)
}
\endqml
- \sa Path, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg, PathMove, PathPolyline
+ \sa Path, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg, PathMove, PathPolyline, PathRectangle
*/
/*!
@@ -1467,7 +1475,7 @@ void QQuickPathQuad::addToPath(QPainterPath &path, const QQuickPathData &data)
\endqml
\endtable
- \sa Path, PathQuad, PathLine, PathArc, PathAngleArc, PathCurve, PathSvg
+ \sa Path, PathQuad, PathLine, PathArc, PathAngleArc, PathCurve, PathSvg, PathRectangle
*/
/*!
@@ -2035,7 +2043,7 @@ void QQuickPathArc::addToPath(QPainterPath &path, const QQuickPathData &data)
to work as part of a larger path (specifying start and end), PathAngleArc is designed
to make a path where the arc is primary (such as a circular progress indicator) more intuitive.
- \sa Path, PathLine, PathQuad, PathCubic, PathCurve, PathSvg, PathArc
+ \sa Path, PathLine, PathQuad, PathCubic, PathCurve, PathSvg, PathArc, PathRectangle
*/
/*!
@@ -2252,6 +2260,268 @@ void QQuickPathSvg::addToPath(QPainterPath &path, const QQuickPathData &)
/****************************************************************************/
/*!
+ \qmltype PathRectangle
+ \instantiates QQuickPathRectangle
+ \inqmlmodule QtQuick
+ \ingroup qtquick-animation-paths
+ \brief Defines a rectangle with optionally rounded corners.
+ \since QtQuick 6.8
+
+ PathRectangle provides an easy way to specify a rectangle, optionally with rounded corners. The
+ API corresponds to that of the \l Rectangle item.
+
+ \sa Path, PathLine, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathRectangle::x
+ \qmlproperty real QtQuick::PathRectangle::y
+
+ Defines the top left corner of the rectangle.
+
+ Unless that corner is rounded, this will also be the start and end point of the path.
+
+ \sa relativeX, relativeY
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathRectangle::relativeX
+ \qmlproperty real QtQuick::PathRectangle::relativeY
+
+ Defines the top left corner of the rectangle relative to the path's start point.
+
+ If both a relative and absolute end position are specified for a single axis, the relative
+ position will be used.
+
+ Relative and absolute positions can be mixed, for example it is valid to set a relative x
+ and an absolute y.
+
+ \sa x, y
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathRectangle::width
+ \qmlproperty real QtQuick::PathRectangle::height
+
+ Defines the width and height of the rectangle.
+
+ \sa x, y
+*/
+
+qreal QQuickPathRectangle::width() const
+{
+ return _width;
+}
+
+void QQuickPathRectangle::setWidth(qreal width)
+{
+ if (_width == width)
+ return;
+
+ _width = width;
+ emit widthChanged();
+ emit changed();
+}
+
+qreal QQuickPathRectangle::height() const
+{
+ return _height;
+}
+
+void QQuickPathRectangle::setHeight(qreal height)
+{
+ if (_height == height)
+ return;
+
+ _height = height;
+ emit heightChanged();
+ emit changed();
+}
+
+/*!
+ \qmlproperty real QtQuick::PathRectangle::strokeAdjustment
+
+ This property defines the stroke width adjustment to the rectangle coordinates.
+
+ When used in a \l ShapePath with stroking enabled, the actual stroked rectangle will by default
+ extend beyond the defined rectangle by half the stroke width on all sides. This is the expected
+ behavior since the path defines the midpoint line of the stroking, and corresponds to QPainter
+ and SVG rendering.
+
+ If one instead wants the defined rectangle to be the outer edge of the stroked rectangle, like
+ a \l Rectangle item with a border, one can set strokeAdjustment to the stroke width. This will
+ effectively shift all edges inwards by half the stroke width. Like in the following example:
+
+ \qml
+ ShapePath {
+ id: myRec
+ fillColor: "white"
+ strokeColor: "black"
+ strokeWidth: 16
+ joinStyle: ShapePath.MiterJoin
+
+ PathRectangle { x: 10; y: 10; width: 200; height: 100; strokeAdjustment: myRec.strokeWidth }
+ }
+ \endqml
+*/
+
+qreal QQuickPathRectangle::strokeAdjustment() const
+{
+ return _strokeAdjustment;
+}
+
+void QQuickPathRectangle::setStrokeAdjustment(qreal newStrokeAdjustment)
+{
+ if (_strokeAdjustment == newStrokeAdjustment)
+ return;
+ _strokeAdjustment = newStrokeAdjustment;
+ emit strokeAdjustmentChanged();
+ emit changed();
+}
+
+/*!
+ \qmlproperty real QtQuick::PathRectangle::radius
+
+ This property defines the corner radius used to define a rounded rectangle.
+
+ If radius is a positive value, the rectangle path will be defined as a rounded rectangle,
+ otherwise it will be defined as a normal rectangle.
+
+ This property may be overridden by the individual corner radius properties.
+
+ \sa topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius
+*/
+
+qreal QQuickPathRectangle::radius() const
+{
+ return _extra.isAllocated() ? _extra->radius : 0;
+}
+
+void QQuickPathRectangle::setRadius(qreal newRadius)
+{
+ if (_extra.value().radius == newRadius)
+ return;
+ _extra->radius = newRadius;
+ emit radiusChanged();
+ if (_extra->cornerRadii[Qt::TopLeftCorner] < 0)
+ emit topLeftRadiusChanged();
+ if (_extra->cornerRadii[Qt::TopRightCorner] < 0)
+ emit topRightRadiusChanged();
+ if (_extra->cornerRadii[Qt::BottomLeftCorner] < 0)
+ emit bottomLeftRadiusChanged();
+ if (_extra->cornerRadii[Qt::BottomRightCorner] < 0)
+ emit bottomRightRadiusChanged();
+ emit changed();
+}
+
+/*!
+ \qmlproperty real QtQuick::PathRectangle::topLeftRadius
+ \qmlproperty real QtQuick::PathRectangle::topRightRadius
+ \qmlproperty real QtQuick::PathRectangle::bottomLeftRadius
+ \qmlproperty real QtQuick::PathRectangle::bottomRightRadius
+
+ If set, these properties define the individual corner radii. A zero value defines that corner
+ to be sharp, while a positive value defines it to be rounded. When unset, the value of \l
+ radius is used instead.
+
+ These properties are unset by default. Assign \c undefined to them to return them to the unset
+ state.
+
+ \sa radius
+*/
+
+qreal QQuickPathRectangle::cornerRadius(Qt::Corner corner) const
+{
+ if (_extra.isAllocated())
+ return _extra->cornerRadii[corner] < 0 ? _extra->radius : _extra->cornerRadii[corner];
+ else
+ return 0;
+}
+
+void QQuickPathRectangle::setCornerRadius(Qt::Corner corner, qreal newCornerRadius)
+{
+ if (newCornerRadius < 0 || _extra.value().cornerRadii[corner] == newCornerRadius)
+ return;
+ _extra->cornerRadii[corner] = newCornerRadius;
+ emitCornerRadiusChanged(corner);
+}
+
+void QQuickPathRectangle::resetCornerRadius(Qt::Corner corner)
+{
+ if (!_extra.isAllocated() || _extra->cornerRadii[corner] < 0)
+ return;
+ _extra->cornerRadii[corner] = -1;
+ emitCornerRadiusChanged(corner);
+}
+
+void QQuickPathRectangle::emitCornerRadiusChanged(Qt::Corner corner)
+{
+ switch (corner) {
+ case Qt::TopLeftCorner:
+ emit topLeftRadiusChanged();
+ break;
+ case Qt::TopRightCorner:
+ emit topRightRadiusChanged();
+ break;
+ case Qt::BottomLeftCorner:
+ emit bottomLeftRadiusChanged();
+ break;
+ case Qt::BottomRightCorner:
+ emit bottomRightRadiusChanged();
+ break;
+ }
+ emit changed();
+}
+
+void QQuickPathRectangle::addToPath(QPainterPath &path, const QQuickPathData &data)
+{
+ QRectF rect(positionForCurve(data, path.currentPosition()), QSizeF(_width, _height));
+
+ qreal halfStroke = _strokeAdjustment * 0.5;
+ rect.adjust(halfStroke, halfStroke, -halfStroke, -halfStroke);
+ if (rect.isEmpty())
+ return;
+
+ if (!_extra.isAllocated()) {
+ // No rounded corners
+ path.addRect(rect);
+ } else {
+ // Radii must not exceed half of the width or half of the height
+ const qreal maxDiameter = qMin(rect.width(), rect.height());
+ const qreal generalDiameter = qMax(qreal(0), qMin(maxDiameter, 2 * _extra->radius));
+ auto effectiveDiameter = [&](Qt::Corner corner) {
+ qreal radius = _extra->cornerRadii[corner];
+ return radius < 0 ? generalDiameter : qMin(maxDiameter, 2 * radius);
+ };
+ const qreal diamTL = effectiveDiameter(Qt::TopLeftCorner);
+ const qreal diamTR = effectiveDiameter(Qt::TopRightCorner);
+ const qreal diamBL = effectiveDiameter(Qt::BottomLeftCorner);
+ const qreal diamBR = effectiveDiameter(Qt::BottomRightCorner);
+
+ path.moveTo(rect.left() + diamTL * 0.5, rect.top());
+ if (diamTR)
+ path.arcTo(QRectF(QPointF(rect.right() - diamTR, rect.top()), QSizeF(diamTR, diamTR)), 90, -90);
+ else
+ path.lineTo(rect.topRight());
+ if (diamBR)
+ path.arcTo(QRectF(QPointF(rect.right() - diamBR, rect.bottom() - diamBR), QSizeF(diamBR, diamBR)), 0, -90);
+ else
+ path.lineTo(rect.bottomRight());
+ if (diamBL)
+ path.arcTo(QRectF(QPointF(rect.left(), rect.bottom() - diamBL), QSizeF(diamBL, diamBL)), 270, -90);
+ else
+ path.lineTo(rect.bottomLeft());
+ if (diamTL)
+ path.arcTo(QRectF(rect.topLeft(), QSizeF(diamTL, diamTL)), 180, -90);
+ else
+ path.lineTo(rect.topLeft());
+ path.closeSubpath();
+ }
+}
+
+/****************************************************************************/
+
+/*!
\qmltype PathPercent
\instantiates QQuickPathPercent
\inqmlmodule QtQuick
@@ -2811,11 +3081,18 @@ void QQuickPathMultiline::addToPath(QPainterPath &path, const QQuickPathData &)
*/
/*!
- \qmlproperty object QtQuick::PathText::font.contextFontMerging
+ \qmlproperty bool QtQuick::PathText::font.contextFontMerging
\since 6.8
\include qquicktext.cpp qml-font-context-font-merging
*/
+
+/*!
+ \qmlproperty bool QtQuick::PathText::font.preferTypoLineMetrics
+ \since 6.8
+
+ \include qquicktext.cpp qml-font-prefer-typo-line-metrics
+*/
void QQuickPathText::updatePath() const
{
if (!_path.isEmpty())
diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h
index 55400d2ddd..173bdd2fea 100644
--- a/src/quick/util/qquickpath_p.h
+++ b/src/quick/util/qquickpath_p.h
@@ -22,6 +22,7 @@ QT_REQUIRE_CONFIG(quick_path);
#include <qqml.h>
#include <private/qqmlnullablevalue_p.h>
+#include <private/qlazilyallocated_p.h>
#include <private/qbezier_p.h>
#include <private/qtquickglobal_p.h>
@@ -397,6 +398,83 @@ private:
QString _path;
};
+class Q_QUICK_EXPORT QQuickPathRectangle : public QQuickCurve
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged FINAL)
+ Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged FINAL)
+ Q_PROPERTY(qreal strokeAdjustment READ strokeAdjustment WRITE setStrokeAdjustment NOTIFY strokeAdjustmentChanged FINAL)
+ Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged FINAL)
+ Q_PROPERTY(qreal topLeftRadius READ topLeftRadius WRITE setTopLeftRadius RESET resetTopLeftRadius NOTIFY topLeftRadiusChanged FINAL)
+ Q_PROPERTY(qreal topRightRadius READ topRightRadius WRITE setTopRightRadius NOTIFY topRightRadiusChanged RESET resetTopRightRadius FINAL)
+ Q_PROPERTY(qreal bottomLeftRadius READ bottomLeftRadius WRITE setBottomLeftRadius NOTIFY bottomLeftRadiusChanged RESET resetBottomLeftRadius FINAL)
+ Q_PROPERTY(qreal bottomRightRadius READ bottomRightRadius WRITE setBottomRightRadius NOTIFY bottomRightRadiusChanged RESET resetBottomRightRadius FINAL)
+
+ QML_NAMED_ELEMENT(PathRectangle)
+ QML_ADDED_IN_VERSION(6, 8)
+public:
+ QQuickPathRectangle(QObject *parent = nullptr) : QQuickCurve(parent) {}
+
+ qreal width() const;
+ void setWidth(qreal width);
+
+ qreal height() const;
+ void setHeight(qreal height);
+
+ qreal strokeAdjustment() const;
+ void setStrokeAdjustment(qreal newStrokeAdjustment);
+
+ qreal radius() const;
+ void setRadius(qreal newRadius);
+
+ qreal topLeftRadius() const { return cornerRadius(Qt::TopLeftCorner); }
+ void setTopLeftRadius(qreal radius) { setCornerRadius(Qt::TopLeftCorner, radius); }
+ void resetTopLeftRadius() { resetCornerRadius(Qt::TopLeftCorner); }
+
+ qreal topRightRadius() const { return cornerRadius(Qt::TopRightCorner); }
+ void setTopRightRadius(qreal radius) { setCornerRadius(Qt::TopRightCorner, radius); }
+ void resetTopRightRadius() { resetCornerRadius(Qt::TopRightCorner); }
+
+ qreal bottomLeftRadius() const { return cornerRadius(Qt::BottomLeftCorner); }
+ void setBottomLeftRadius(qreal radius) { setCornerRadius(Qt::BottomLeftCorner, radius); }
+ void resetBottomLeftRadius() { resetCornerRadius(Qt::BottomLeftCorner); }
+
+ qreal bottomRightRadius() const { return cornerRadius(Qt::BottomRightCorner); }
+ void setBottomRightRadius(qreal radius) { setCornerRadius(Qt::BottomRightCorner, radius); }
+ void resetBottomRightRadius() { resetCornerRadius(Qt::BottomRightCorner); }
+
+ qreal cornerRadius(Qt::Corner corner) const;
+ void setCornerRadius(Qt::Corner corner, qreal newCornerRadius);
+ void resetCornerRadius(Qt::Corner corner);
+
+ void addToPath(QPainterPath &path, const QQuickPathData &) override;
+
+Q_SIGNALS:
+ void widthChanged();
+ void heightChanged();
+ void strokeAdjustmentChanged();
+ void radiusChanged();
+ void topLeftRadiusChanged();
+ void topRightRadiusChanged();
+ void bottomLeftRadiusChanged();
+ void bottomRightRadiusChanged();
+
+private:
+ void emitCornerRadiusChanged(Qt::Corner corner);
+
+ qreal _width = 0;
+ qreal _height = 0;
+ qreal _strokeAdjustment = 0;
+ struct ExtraData
+ {
+ ExtraData() { std::fill_n(cornerRadii, 4, -1); }
+ qreal radius = 0;
+ qreal cornerRadii[4];
+ };
+ QLazilyAllocated<ExtraData> _extra;
+};
+
class Q_QUICK_EXPORT QQuickPathPercent : public QQuickPathElement
{
Q_OBJECT
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 10cc407c21..5b4aeb7e16 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -58,8 +58,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::Literals::StringLiterals;
-Q_DECLARE_LOGGING_CATEGORY(lcQsgLeak)
-
#if defined(QT_DEBUG) && QT_CONFIG(thread)
class ThreadAffinityMarker
{
@@ -98,7 +96,7 @@ private:
const QLatin1String QQuickPixmap::itemGrabberScheme = QLatin1String("itemgrabber");
-Q_LOGGING_CATEGORY(lcImg, "qt.quick.image")
+Q_STATIC_LOGGING_CATEGORY(lcImg, "qt.quick.image")
/*! \internal
The maximum currently-unused image data that can be stored for potential
@@ -608,20 +606,18 @@ QQuickPixmapReader::~QQuickPixmapReader()
delete reply;
}
jobs.clear();
-#if QT_CONFIG(qml_network)
const auto cancelJob = [this](QQuickPixmapReply *reply) {
if (reply->loading) {
cancelledJobs.append(reply);
reply->data = nullptr;
}
};
-
+#if QT_CONFIG(qml_network)
for (auto *reply : std::as_const(networkJobs))
cancelJob(reply);
-
+#endif
for (auto *reply : std::as_const(asyncResponses))
cancelJob(reply);
-#endif
#if !QT_CONFIG(quick_pixmap_cache_threaded_download)
// In this case we won't be waiting, but we are on the correct thread already, so we can
// perform housekeeping synchronously now.
@@ -642,7 +638,6 @@ QQuickPixmapReader::~QQuickPixmapReader()
wait();
#endif
-#if QT_CONFIG(qml_network)
// While we've been waiting, the other thread may have added
// more replies. No one will care about them anymore.
@@ -651,16 +646,17 @@ QQuickPixmapReader::~QQuickPixmapReader()
reply->data->reply = nullptr;
delete reply;
};
-
+#if QT_CONFIG(qml_network)
for (QQuickPixmapReply *reply : std::as_const(networkJobs))
deleteReply(reply);
-
+#endif
for (QQuickPixmapReply *reply : std::as_const(asyncResponses))
deleteReply(reply);
+#if QT_CONFIG(qml_network)
networkJobs.clear();
- asyncResponses.clear();
#endif
+ asyncResponses.clear();
}
#if QT_CONFIG(qml_network)
@@ -805,7 +801,9 @@ void QQuickPixmapReader::processJobs()
// cancel any jobs already started
reply->close();
}
- } else {
+ } else
+#endif
+ {
QQuickImageResponse *asyncResponse = asyncResponses.key(job);
if (asyncResponse) {
asyncResponses.remove(asyncResponse);
@@ -813,7 +811,6 @@ void QQuickPixmapReader::processJobs()
}
}
PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(job->url));
-#endif
// deleteLater, since not owned by this thread
job->deleteLater();
}
diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h
index a5e69df3be..377c9831d7 100644
--- a/src/quick/util/qquickprofiler_p.h
+++ b/src/quick/util/qquickprofiler_p.h
@@ -22,6 +22,7 @@
#include <QtQml/private/qqmlprofilerdefinitions_p.h>
#endif
+#include <QtCore/private/qnumeric_p.h>
#include <QtCore/qurl.h>
#include <QtCore/qsize.h>
#include <QtCore/qmutex.h>
@@ -128,7 +129,7 @@ public:
template<SceneGraphFrameType type>
qint64 *timings()
{
- if (type < NumRenderThreadFrameTypes)
+ if constexpr (type < NumRenderThreadFrameTypes)
return renderThreadTimings.localData().values[type];
else
return guiThreadTimings.values[type - NumRenderThreadFrameTypes];
@@ -206,11 +207,12 @@ public:
static void animationFrame(qint64 delta, AnimationThread threadId)
{
- int animCount = QUnifiedTimer::instance()->runningAnimationCount();
+ const qsizetype animCount = QUnifiedTimer::instance()->runningAnimationCount();
if (animCount > 0 && delta > 0) {
s_instance->processMessage(QQuickProfilerData(s_instance->timestamp(), 1 << Event,
- 1 << AnimationFrame, 1000 / (int)delta /* trim fps to integer */, animCount,
+ 1 << AnimationFrame, 1000 / (int)delta /* trim fps to integer */,
+ qt_saturate<int>(animCount),
threadId));
}
}
diff --git a/src/quick/util/qquicksmoothedanimation_p_p.h b/src/quick/util/qquicksmoothedanimation_p_p.h
index 2e0fe5be15..e57b472b01 100644
--- a/src/quick/util/qquicksmoothedanimation_p_p.h
+++ b/src/quick/util/qquicksmoothedanimation_p_p.h
@@ -21,7 +21,7 @@
#include "qquickanimation_p_p.h"
#include <private/qobject_p.h>
-#include <QBasicTimer>
+#include <QTimer>
QT_BEGIN_NAMESPACE
class QSmoothedAnimation;
diff --git a/src/quick/util/qquickstate_p.h b/src/quick/util/qquickstate_p.h
index b829248e24..66d0303162 100644
--- a/src/quick/util/qquickstate_p.h
+++ b/src/quick/util/qquickstate_p.h
@@ -27,6 +27,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcStates)
+
class QQuickStateActionEvent;
class QQmlBinding;
class QQmlExpression;
diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp
index f61261035f..8fb3130e35 100644
--- a/src/quick/util/qquickstategroup.cpp
+++ b/src/quick/util/qquickstategroup.cpp
@@ -19,8 +19,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-Q_DECLARE_LOGGING_CATEGORY(lcStates)
-
class QQuickStateGroupPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQuickStateGroup)
diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp
index a595dbcbc2..bc7c38e869 100644
--- a/src/quick/util/qquickstyledtext.cpp
+++ b/src/quick/util/qquickstyledtext.cpp
@@ -11,7 +11,7 @@
#include <QQmlContext>
#include <QtGui/private/qtexthtmlparser_p.h>
-Q_LOGGING_CATEGORY(lcStyledText, "qt.quick.styledtext")
+Q_STATIC_LOGGING_CATEGORY(lcStyledText, "qt.quick.styledtext")
/*
QQuickStyledText supports few tags:
diff --git a/src/quick/util/qquicktimeline.cpp b/src/quick/util/qquicktimeline.cpp
index a47e5ba5ff..d79d835900 100644
--- a/src/quick/util/qquicktimeline.cpp
+++ b/src/quick/util/qquicktimeline.cpp
@@ -18,7 +18,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcTl, "qt.quick.timeline")
+Q_STATIC_LOGGING_CATEGORY(lcTl, "qt.quick.timeline")
struct Update {
Update(QQuickTimeLineValue *_g, qreal _v)
diff --git a/src/quick/util/qquicktransitionmanager.cpp b/src/quick/util/qquicktransitionmanager.cpp
index 700e06a8ba..6788cc73a9 100644
--- a/src/quick/util/qquicktransitionmanager.cpp
+++ b/src/quick/util/qquicktransitionmanager.cpp
@@ -15,8 +15,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcStates)
-
class QQuickTransitionManagerPrivate
{
public:
diff --git a/src/quick/util/qquickvaluetypes.cpp b/src/quick/util/qquickvaluetypes.cpp
index 350f55e143..265c763566 100644
--- a/src/quick/util/qquickvaluetypes.cpp
+++ b/src/quick/util/qquickvaluetypes.cpp
@@ -763,6 +763,135 @@ bool QQuickMatrix4x4ValueType::fuzzyEquals(const QMatrix4x4 &m) const
return qFuzzyCompare(v, m);
}
+/*!
+ \qmltype PlanarTransform
+ \inqmlmodule QtQuick
+ \since 6.8
+
+ \brief Provides utility functions for matrix4x4 when used for 2D transforms.
+
+ The \c PlanarTransform is a global object with utility functions.
+
+ It is not instantiable; to use it, call the members of the global \c PlanarTransform object
+ directly. For example:
+
+ \qml
+ Item {
+ transform: Matrix4x4 { matrix: PlanarTransform.fromAffineMatrix(1, 0, 0.36, 1, -36, 0) }
+ }
+ \endqml
+*/
+
+QQuickPlanarTransform::QQuickPlanarTransform(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ \qmlmethod matrix4x4 PlanarTransform::identity()
+
+ Returns a matrix4x4 for the identity transform.
+
+ This is equivalent to \l Qt::matrix4x4().
+*/
+
+QMatrix4x4 QQuickPlanarTransform::identity()
+{
+ return QMatrix4x4();
+}
+
+/*!
+ \qmlmethod matrix4x4 PlanarTransform::fromAffineMatrix(real scaleX, real shearY,
+ real shearX, real scaleY,
+ real translateX, real translateY)
+
+ Returns a matrix4x4 for an affine (non-projecting) 2D transform with the specified values.
+
+ This method and its argument order correspond to SVG's \c matrix() function and the
+ six-argument QTransform constructor. The result is this 4x4 matrix:
+
+ \table
+ \row \li \a scaleX \li \a shearX \li 0 \li \a translateX
+ \row \li \a shearY \li \a scaleY \li 0 \li \a translateY
+ \row \li 0 \li 0 \li 1 \li 0
+ \row \li 0 \li 0 \li 0 \li 1
+ \endtable
+*/
+
+QMatrix4x4 QQuickPlanarTransform::fromAffineMatrix(float scaleX, float shearY,
+ float shearX, float scaleY,
+ float translateX, float translateY)
+{
+ return QMatrix4x4(scaleX, shearX, 0, translateX,
+ shearY, scaleY, 0, translateY,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
+}
+
+/*!
+ \qmlmethod matrix4x4 PlanarTransform::fromTranslate(real translateX, real translateY)
+
+ Returns a matrix4x4 for a 2D transform that translates by \a translateX horizontally and
+ \a translateY vertically.
+*/
+QMatrix4x4 QQuickPlanarTransform::fromTranslate(float translateX, float translateY)
+{
+ QMatrix4x4 xf;
+ xf.translate(translateX, translateY);
+ return xf;
+}
+
+/*!
+ \qmlmethod matrix4x4 PlanarTransform::fromScale(real scaleX, real scaleY, real originX, real originY)
+
+ Returns a matrix4x4 for a 2D transform that scales by \a scaleX horizontally and \a scaleY
+ vertically, centered at the point (\a originX, \a originY).
+
+ \a originX and \a originY are optional and default to (0, 0).
+*/
+QMatrix4x4 QQuickPlanarTransform::fromScale(float scaleX, float scaleY, float originX, float originY)
+{
+ QMatrix4x4 xf;
+ xf.translate(originX, originY);
+ xf.scale(scaleX, scaleY);
+ xf.translate(-originX, -originY);
+ return xf;
+}
+
+/*!
+ \qmlmethod matrix4x4 PlanarTransform::fromRotate(real angle, real originX, real originY)
+
+ Returns a matrix4x4 for a 2D transform that rotates by \a angle degrees around the point (\a
+ originX, \a originY).
+
+ \a originX and \a originY are optional and default to (0, 0).
+*/
+QMatrix4x4 QQuickPlanarTransform::fromRotate(float angle, float originX, float originY)
+{
+ QMatrix4x4 xf;
+ xf.translate(originX, originY);
+ xf.rotate(angle, 0, 0, 1);
+ xf.translate(-originX, -originY);
+ return xf;
+}
+
+/*!
+ \qmlmethod matrix4x4 PlanarTransform::fromShear(float shearX, float shearY, float originX, float originY)
+
+ Returns a matrix4x4 for a 2D transform that shears by \a shearX horizontally and \a shearY
+ vertically, centered at the point (\a originX, \a originY).
+
+ \a originX and \a originY are optional and default to (0, 0).
+*/
+QMatrix4x4 QQuickPlanarTransform::fromShear(float shearX, float shearY, float originX, float originY)
+{
+ QMatrix4x4 xf;
+ xf.translate(originX, originY);
+ xf *= QMatrix4x4(1, shearX, 0, 0, shearY, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ xf.translate(-originX, -originY);
+ return xf;
+}
+
template<typename T>
void setFontProperty(QFont &font, void (QFont::*setter)(T value), QString name,
const QJSValue &params, bool *ok)
@@ -809,27 +938,45 @@ QVariant QQuickFontValueType::create(const QJSValue &params)
setFontProperty(ret, &QFont::setPixelSize, QStringLiteral("pixelSize"), params, &ok);
setFontProperty(ret, &QFont::setPointSize, QStringLiteral("pointSize"), params, &ok);
setFontProperty(ret, &QFont::setStrikeOut, QStringLiteral("strikeout"), params, &ok);
+ setFontProperty(ret, &QFont::setStyleName, QStringLiteral("styleName"), params, &ok);
setFontProperty(ret, &QFont::setUnderline, QStringLiteral("underline"), params, &ok);
setFontProperty(ret, &QFont::setWeight, QStringLiteral("weight"), params, &ok);
setFontProperty(ret, &QFont::setWordSpacing, QStringLiteral("wordSpacing"), params, &ok);
setFontProperty(ret, &QFont::setHintingPreference, QStringLiteral("hintingPreference"), params, &ok);
setFontProperty(ret, &QFont::setKerning, QStringLiteral("kerning"), params, &ok);
- const QJSValue vlspac = params.property(QStringLiteral("letterSpacing"));
- if (vlspac.isNumber()) {
- ret.setLetterSpacing(QFont::AbsoluteSpacing, vlspac.toNumber());
- ok = true;
+ {
+ const QJSValue vlspac = params.property(QStringLiteral("letterSpacing"));
+ if (vlspac.isNumber()) {
+ ret.setLetterSpacing(QFont::AbsoluteSpacing, vlspac.toNumber());
+ ok = true;
+ }
}
- const QJSValue vshaping = params.property(QStringLiteral("preferShaping"));
- if (vshaping.isBool()) {
- const bool enable = vshaping.toBool();
- const QFont::StyleStrategy strategy = ret.styleStrategy();
- if (enable)
- ret.setStyleStrategy(QFont::StyleStrategy(strategy & ~QFont::PreferNoShaping));
- else
- ret.setStyleStrategy(QFont::StyleStrategy(strategy | QFont::PreferNoShaping));
- ok = true;
+ {
+ const QJSValue vshaping = params.property(QStringLiteral("preferShaping"));
+ if (vshaping.isBool()) {
+ const bool enable = vshaping.toBool();
+ const QFont::StyleStrategy strategy = ret.styleStrategy();
+ if (enable)
+ ret.setStyleStrategy(QFont::StyleStrategy(strategy & ~QFont::PreferNoShaping));
+ else
+ ret.setStyleStrategy(QFont::StyleStrategy(strategy | QFont::PreferNoShaping));
+ ok = true;
+ }
+ }
+
+ {
+ const QJSValue typoMetrics = params.property(QStringLiteral("preferTypoLineMetrics"));
+ if (typoMetrics.isBool()) {
+ const bool enable = typoMetrics.toBool();
+ const QFont::StyleStrategy strategy = ret.styleStrategy();
+ if (enable)
+ ret.setStyleStrategy(QFont::StyleStrategy(strategy & ~QFont::PreferTypoLineMetrics));
+ else
+ ret.setStyleStrategy(QFont::StyleStrategy(strategy | QFont::PreferTypoLineMetrics));
+ ok = true;
+ }
}
return ok ? ret : QVariant();
@@ -1093,6 +1240,19 @@ void QQuickFontValueType::setContextFontMerging(bool enable)
v.setStyleStrategy(static_cast<QFont::StyleStrategy>(v.styleStrategy() & ~QFont::ContextFontMerging));
}
+bool QQuickFontValueType::preferTypoLineMetrics() const
+{
+ return (v.styleStrategy() & QFont::PreferTypoLineMetrics) != 0;
+}
+
+void QQuickFontValueType::setPreferTypoLineMetrics(bool enable)
+{
+ if (enable)
+ v.setStyleStrategy(static_cast<QFont::StyleStrategy>(v.styleStrategy() | QFont::PreferTypoLineMetrics));
+ else
+ v.setStyleStrategy(static_cast<QFont::StyleStrategy>(v.styleStrategy() & ~QFont::PreferTypoLineMetrics));
+}
+
QVariant QQuickColorSpaceValueType::create(const QJSValue &params)
{
if (!params.isObject())
diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h
index c203d12fab..6fd33c1323 100644
--- a/src/quick/util/qquickvaluetypes_p.h
+++ b/src/quick/util/qquickvaluetypes_p.h
@@ -54,6 +54,7 @@ class Q_QUICK_EXPORT QQuickColorValueType
public:
static QVariant create(const QJSValue &params);
+ Q_INVOKABLE QQuickColorValueType() = default;
Q_INVOKABLE QQuickColorValueType(const QString &string);
Q_INVOKABLE QString toString() const;
@@ -102,6 +103,7 @@ class Q_QUICK_EXPORT QQuickVector2DValueType
public:
static QVariant create(const QJSValue &params);
+ Q_INVOKABLE QQuickVector2DValueType() = default;
Q_INVOKABLE QString toString() const;
qreal x() const;
@@ -140,6 +142,7 @@ class Q_QUICK_EXPORT QQuickVector3DValueType
public:
static QVariant create(const QJSValue &params);
+ Q_INVOKABLE QQuickVector3DValueType() = default;
Q_INVOKABLE QString toString() const;
qreal x() const;
@@ -183,6 +186,7 @@ class Q_QUICK_EXPORT QQuickVector4DValueType
public:
static QVariant create(const QJSValue &params);
+ Q_INVOKABLE QQuickVector4DValueType() = default;
Q_INVOKABLE QString toString() const;
qreal x() const;
@@ -227,6 +231,7 @@ class Q_QUICK_EXPORT QQuickQuaternionValueType
public:
static QVariant create(const QJSValue &params);
+ Q_INVOKABLE QQuickQuaternionValueType() = default;
Q_INVOKABLE QString toString() const;
qreal scalar() const;
@@ -288,6 +293,8 @@ class Q_QUICK_EXPORT QQuickMatrix4x4ValueType
public:
static QVariant create(const QJSValue &params);
+ Q_INVOKABLE QQuickMatrix4x4ValueType() = default;
+
qreal m11() const { return v(0, 0); }
qreal m12() const { return v(0, 1); }
qreal m13() const { return v(0, 2); }
@@ -353,6 +360,28 @@ public:
operator QMatrix4x4() const { return v; }
};
+class Q_QUICK_EXPORT QQuickPlanarTransform : public QObject
+{
+ Q_OBJECT
+ QML_SINGLETON
+ QML_NAMED_ELEMENT(PlanarTransform)
+ QML_ADDED_IN_VERSION(6, 8)
+
+public:
+ explicit QQuickPlanarTransform(QObject *parent = nullptr);
+
+ Q_INVOKABLE static QMatrix4x4 identity();
+ Q_INVOKABLE static QMatrix4x4 fromAffineMatrix(float scaleX, float shearY,
+ float shearX, float scaleY,
+ float translateX, float translateY);
+ Q_INVOKABLE static QMatrix4x4 fromTranslate(float translateX, float translateY);
+ Q_INVOKABLE static QMatrix4x4 fromScale(float scaleX, float scaleY,
+ float originX = 0, float originY = 0);
+ Q_INVOKABLE static QMatrix4x4 fromRotate(float angle,float originX = 0, float originY = 0);
+ Q_INVOKABLE static QMatrix4x4 fromShear(float shearX, float shearY,
+ float originX = 0, float originY = 0);
+};
+
namespace QQuickFontEnums
{
Q_NAMESPACE_EXPORT(Q_QUICK_EXPORT)
@@ -410,6 +439,7 @@ class Q_QUICK_EXPORT QQuickFontValueType
Q_PROPERTY(QVariantMap features READ features WRITE setFeatures FINAL)
Q_PROPERTY(QVariantMap variableAxes READ variableAxes WRITE setVariableAxes FINAL)
Q_PROPERTY(bool contextFontMerging READ contextFontMerging WRITE setContextFontMerging FINAL)
+ Q_PROPERTY(bool preferTypoLineMetrics READ preferTypoLineMetrics WRITE setPreferTypoLineMetrics FINAL)
QML_VALUE_TYPE(font)
QML_FOREIGN(QFont)
@@ -420,6 +450,7 @@ class Q_QUICK_EXPORT QQuickFontValueType
public:
static QVariant create(const QJSValue &value);
+ Q_INVOKABLE QQuickFontValueType() = default;
Q_INVOKABLE QString toString() const;
QString family() const;
@@ -479,6 +510,9 @@ public:
bool contextFontMerging() const;
void setContextFontMerging(bool b);
+ bool preferTypoLineMetrics() const;
+ void setPreferTypoLineMetrics(bool b);
+
operator QFont() const { return v; }
};
diff --git a/src/quickcontrols/CMakeLists.txt b/src/quickcontrols/CMakeLists.txt
index 18b170ad82..1a5160a405 100644
--- a/src/quickcontrols/CMakeLists.txt
+++ b/src/quickcontrols/CMakeLists.txt
@@ -17,6 +17,7 @@ qt_internal_add_qml_module(QuickControls2
QtQuick.Controls.Material/auto
QtQuick.Controls.Imagine/auto
QtQuick.Controls.Universal/auto
+ QtQuick.Controls.FluentWinUI3/auto
QtQuick.Controls.Windows/auto
QtQuick.Controls.macOS/auto
QtQuick.Controls.iOS/auto
@@ -43,7 +44,6 @@ qt_internal_add_qml_module(QuickControls2
Qt::Core
Qt::Gui
Qt::Quick
- GENERATE_CPP_EXPORTS
)
qt_internal_extend_target(qtquickcontrols2plugin
@@ -83,6 +83,10 @@ if(QT_FEATURE_quickcontrols2_universal)
add_subdirectory(universal)
endif()
+if(QT_FEATURE_quickcontrols2_fluentwinui3)
+ add_subdirectory(fluentwinui3)
+endif()
+
if(QT_FEATURE_quickcontrols2_macos)
add_subdirectory(macos)
endif()
diff --git a/src/quickcontrols/basic/CMakeLists.txt b/src/quickcontrols/basic/CMakeLists.txt
index a9ed8f1f2a..b5aa4a7fbb 100644
--- a/src/quickcontrols/basic/CMakeLists.txt
+++ b/src/quickcontrols/basic/CMakeLists.txt
@@ -177,7 +177,6 @@ qt_internal_add_qml_module(QuickControls2Basic
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
- GENERATE_CPP_EXPORTS
)
target_sources(qtquickcontrols2basicstyleplugin
diff --git a/src/quickcontrols/basic/ComboBox.qml b/src/quickcontrols/basic/ComboBox.qml
index 7c272a80e8..91774afc42 100644
--- a/src/quickcontrols/basic/ComboBox.qml
+++ b/src/quickcontrols/basic/ComboBox.qml
@@ -99,14 +99,14 @@ T.ComboBox {
width: parent.width
height: parent.height
color: "transparent"
- border.color: palette.mid
+ border.color: control.palette.mid
}
T.ScrollIndicator.vertical: ScrollIndicator { }
}
background: Rectangle {
- color: palette.window
+ color: control.palette.window
}
}
}
diff --git a/src/quickcontrols/basic/Dialog.qml b/src/quickcontrols/basic/Dialog.qml
index c4c59b27fb..41cf18751d 100644
--- a/src/quickcontrols/basic/Dialog.qml
+++ b/src/quickcontrols/basic/Dialog.qml
@@ -26,7 +26,7 @@ T.Dialog {
header: Label {
text: control.title
- visible: control.title
+ visible: parent?.parent === Overlay.overlay && control.title
elide: Label.ElideRight
font.bold: true
padding: 12
diff --git a/src/quickcontrols/basic/Tumbler.qml b/src/quickcontrols/basic/Tumbler.qml
index d3d1254fea..4bd5c5fed2 100644
--- a/src/quickcontrols/basic/Tumbler.qml
+++ b/src/quickcontrols/basic/Tumbler.qml
@@ -13,6 +13,8 @@ T.Tumbler {
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
+ readonly property real __delegateHeight: availableHeight / visibleItemCount
+
delegate: Text {
text: modelData
color: control.visualFocus ? control.palette.highlight : control.palette.text
@@ -35,13 +37,12 @@ T.Tumbler {
delegate: control.delegate
path: Path {
startX: control.contentItem.width / 2
- startY: -control.contentItem.delegateHeight / 2
+ startY: -control.__delegateHeight / 2
+
PathLine {
x: control.contentItem.width / 2
- y: (control.visibleItemCount + 1) * control.contentItem.delegateHeight - control.contentItem.delegateHeight / 2
+ y: (control.visibleItemCount + 1) * control.__delegateHeight - control.__delegateHeight / 2
}
}
-
- property real delegateHeight: control.availableHeight / control.visibleItemCount
}
}
diff --git a/src/quickcontrols/configure.cmake b/src/quickcontrols/configure.cmake
index b146186426..4405a9f915 100644
--- a/src/quickcontrols/configure.cmake
+++ b/src/quickcontrols/configure.cmake
@@ -44,6 +44,12 @@ qt_feature("quickcontrols2-universal" PRIVATE
PURPOSE "Provides a style based on the Universal Design guidelines."
CONDITION QT_FEATURE_quickcontrols2_basic
)
+qt_feature("quickcontrols2-fluentwinui3" PRIVATE
+ SECTION "Quick Controls 2"
+ LABEL "FluentWinUI3"
+ PURPOSE "Provides a style based on the Fluent design and Windows UI 3 style."
+ CONDITION QT_FEATURE_quickcontrols2_fusion
+)
qt_feature("quickcontrols2-macos" PRIVATE
SECTION "Quick Controls 2"
LABEL "macOS"
@@ -65,7 +71,7 @@ qt_feature("quickcontrols2-windows" PRIVATE
qt_configure_add_summary_section(NAME "Qt Quick Controls 2")
qt_configure_add_summary_entry(
TYPE "featureList"
- ARGS "quickcontrols2-basic quickcontrols2-fusion quickcontrols2-imagine quickcontrols2-ios quickcontrols2-material quickcontrols2-universal quickcontrols2-macos quickcontrols2-windows"
+ ARGS "quickcontrols2-basic quickcontrols2-fusion quickcontrols2-fluentwinui3 quickcontrols2-imagine quickcontrols2-ios quickcontrols2-material quickcontrols2-universal quickcontrols2-macos quickcontrols2-windows"
MESSAGE "Styles"
)
qt_configure_end_summary_section() # end of "Qt Quick Controls 2" section
diff --git a/src/quickcontrols/doc/images/qtquickcontrols-menu-native.png b/src/quickcontrols/doc/images/qtquickcontrols-menu-native.png
new file mode 100644
index 0000000000..b7812bf31f
--- /dev/null
+++ b/src/quickcontrols/doc/images/qtquickcontrols-menu-native.png
Binary files differ
diff --git a/src/quickcontrols/doc/images/qtquickcontrols-menu.png b/src/quickcontrols/doc/images/qtquickcontrols-menu.png
index 926c33eed2..11f69cf5e5 100644
--- a/src/quickcontrols/doc/images/qtquickcontrols-menu.png
+++ b/src/quickcontrols/doc/images/qtquickcontrols-menu.png
Binary files differ
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-busyindicator-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-busyindicator-custom.qml
index 951976210a..7e57e6bbe7 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-busyindicator-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-busyindicator-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
BusyIndicator {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-button-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-button-custom.qml
index c9778faa3b..13ac86e549 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-button-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-button-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Button {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-checkbox-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-checkbox-custom.qml
index d3c2f98ec1..1cc413aae3 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-checkbox-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-checkbox-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
CheckBox {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-checkdelegate-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-checkdelegate-custom.qml
index d2d8c622d5..2cee3313eb 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-checkdelegate-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-checkdelegate-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
CheckDelegate {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-combobox-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-combobox-custom.qml
index ff499f6550..0cc408d492 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-combobox-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-combobox-custom.qml
@@ -5,7 +5,7 @@
pragma ComponentBehavior: Bound
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ComboBox {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-delaybutton-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-delaybutton-custom.qml
index 1803556052..861c558e3c 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-delaybutton-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-delaybutton-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
DelayButton {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-dial-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-dial-custom.qml
index 65a7439ea1..06399a318a 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-dial-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-dial-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Dial {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-frame-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-frame-custom.qml
index 51dd757044..8498d9bae2 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-frame-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-frame-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Frame {
background: Rectangle {
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-groupbox-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-groupbox-custom.qml
index 38c0f03366..675e2d5e47 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-groupbox-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-groupbox-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
GroupBox {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-headerview.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-headerview.qml
index b8f6935010..9866e41e97 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-headerview.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-headerview.qml
@@ -16,7 +16,7 @@ ApplicationWindow {
anchors.fill: parent
// The background color will show through the cell
// spacing, and therefore become the grid line color.
- color: Qt.styleHints.appearance === Qt.Light ? palette.mid : palette.midlight
+ color: Application.styleHints.appearance === Qt.Light ? palette.mid : palette.midlight
HorizontalHeaderView {
id: horizontalHeader
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate-custom.qml
index 8dcc860dd7..5e299a9d8f 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ItemDelegate {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate.qml
index 4d7fa30f22..33e9974094 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-itemdelegate.qml
@@ -6,6 +6,7 @@ import QtQuick.Controls
//! [1]
ListView {
+ id: listView
width: 160
height: 240
@@ -13,7 +14,7 @@ ListView {
delegate: ItemDelegate {
text: modelData
- width: parent.width
+ width: listView.width
onClicked: console.log("clicked:", modelData)
required property string modelData
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-label-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-label-custom.qml
index 0443e4e357..291d04948f 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-label-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-label-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Label {
text: qsTr("Label")
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-menu-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-menu-custom.qml
index 6d1c587f74..a0b59adffd 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-menu-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-menu-custom.qml
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ApplicationWindow {
id: window
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-menubar-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-menubar-custom.qml
index d76f4f56cd..ef55a5f4c2 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-menubar-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-menubar-custom.qml
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ApplicationWindow {
id: window
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-menuseparator-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-menuseparator-custom.qml
index 81c1e7a7f5..fbc024aa57 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-menuseparator-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-menuseparator-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Item {
id: window
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-pageindicator-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-pageindicator-custom.qml
index 93c2045fc3..14b4131c75 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-pageindicator-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-pageindicator-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
PageIndicator {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-pane-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-pane-custom.qml
index 4663ae9138..aca3f73dc6 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-pane-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-pane-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Pane {
background: Rectangle {
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-popup-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-popup-custom.qml
index bf054f0b3a..cae29d238d 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-popup-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-popup-custom.qml
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
import QtQuick.Window
Item {
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-progressbar-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-progressbar-custom.qml
index ebfbaff62e..97cad51926 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-progressbar-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-progressbar-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ProgressBar {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-radiobutton-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-radiobutton-custom.qml
index 731c67f6b2..3fa1659eec 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-radiobutton-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-radiobutton-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
RadioButton {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-radiodelegate-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-radiodelegate-custom.qml
index 93feeeeece..55c571fab1 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-radiodelegate-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-radiodelegate-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
RadioDelegate {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-rangeslider-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-rangeslider-custom.qml
index 86e71b3175..a83ebe8240 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-rangeslider-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-rangeslider-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
RangeSlider {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-scrollbar-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-scrollbar-custom.qml
index 5ad266dc93..d97627f083 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-scrollbar-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-scrollbar-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ScrollBar {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-scrollindicator-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-scrollindicator-custom.qml
index 8c517b8221..c46832b2c3 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-scrollindicator-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-scrollindicator-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ScrollIndicator {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-scrollview-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-scrollview-custom.qml
index 4c1ec3d29a..05c4ce413e 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-scrollview-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-scrollview-custom.qml
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Item {
width: 200
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-slider-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-slider-custom.qml
index dad6beaa86..26565d3987 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-slider-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-slider-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Slider {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-spinbox-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-spinbox-custom.qml
index c2e6452da6..20b149d611 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-spinbox-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-spinbox-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
SpinBox {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-splitview-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-splitview-custom.qml
index c713c9623d..bb2c29ac6a 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-splitview-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-splitview-custom.qml
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Item {
width: 200
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-stackview-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-stackview-custom.qml
index ec4db1c2de..2f0ea85c77 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-stackview-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-stackview-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
StackView {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-swipedelegate-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-swipedelegate-custom.qml
index 4382e5f9ec..eb691bc9d3 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-swipedelegate-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-swipedelegate-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
SwipeDelegate {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-swipeview-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-swipeview-custom.qml
index 3eae7c28d5..cad89faa06 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-swipeview-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-swipeview-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
SwipeView {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-switch-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-switch-custom.qml
index 6f0cac5b67..c905d4c122 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-switch-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-switch-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Switch {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-switchdelegate-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-switchdelegate-custom.qml
index 2df83b936f..605e5476d5 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-switchdelegate-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-switchdelegate-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
SwitchDelegate {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-tabbar-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-tabbar-custom.qml
index 0310900c42..4017553ef9 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-tabbar-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-tabbar-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
TabBar {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-textarea-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-textarea-custom.qml
index e264a921bb..700cebafe1 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-textarea-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-textarea-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
TextArea {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-textfield-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-textfield-custom.qml
index bed0e25173..740e226662 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-textfield-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-textfield-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
TextField {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-toolbar-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-toolbar-custom.qml
index e4ea2c8b04..75e8f11778 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-toolbar-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-toolbar-custom.qml
@@ -3,7 +3,7 @@
import QtQuick
import QtQuick.Layouts
-import QtQuick.Controls
+import QtQuick.Controls.Basic
//! [file]
ToolBar {
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-toolbutton-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-toolbutton-custom.qml
index ed2c7aaf64..ea81bc9766 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-toolbutton-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-toolbutton-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
ToolButton {
id: control
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-toolseparator-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-toolseparator-custom.qml
index 120428801a..28de544242 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-toolseparator-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-toolseparator-custom.qml
@@ -4,7 +4,7 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
-import QtQuick.Controls
+import QtQuick.Controls.Basic
//! [file]
ToolBar {
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-custom.qml
index 04e390a611..cde93b1abd 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Item {
ToolTip {
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-pressandhold.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-pressandhold.qml
index a2fd762d75..13c90a84f9 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-pressandhold.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-tooltip-pressandhold.qml
@@ -9,7 +9,7 @@ Button {
text: qsTr("Button")
ToolTip.visible: pressed
- ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
+ ToolTip.delay: Application.styleHints.mousePressAndHoldInterval
ToolTip.text: qsTr("This tool tip is shown after pressing and holding the button down.")
}
//! [1]
diff --git a/src/quickcontrols/doc/snippets/qtquickcontrols-tumbler-custom.qml b/src/quickcontrols/doc/snippets/qtquickcontrols-tumbler-custom.qml
index d3dbcf7acc..ee94097acd 100644
--- a/src/quickcontrols/doc/snippets/qtquickcontrols-tumbler-custom.qml
+++ b/src/quickcontrols/doc/snippets/qtquickcontrols-tumbler-custom.qml
@@ -3,7 +3,7 @@
//! [file]
import QtQuick
-import QtQuick.Controls
+import QtQuick.Controls.Basic
Tumbler {
id: control
diff --git a/src/quickcontrols/doc/src/includes/qquickheaderview.qdocinc b/src/quickcontrols/doc/src/includes/qquickheaderview.qdocinc
index 5115149762..fdc191be3f 100644
--- a/src/quickcontrols/doc/src/includes/qquickheaderview.qdocinc
+++ b/src/quickcontrols/doc/src/includes/qquickheaderview.qdocinc
@@ -84,3 +84,21 @@ The warning can be silenced by setting the \l textRole.
\sa QAbstractItemModel::roleNames()
//! [textRole]
+
+//! [movableColumns]
+This property allows the user to move columns in the view. The default value is
+\c false.
+
+\note If this property is set, the HorizontalHeaderView allows the user to drag
+and drop columns at the required position. When syncView is enabled,
+any change will be applied to the corresponding view item.
+//! [movableColumns]
+
+//! [movableRows]
+This property allows the user to move rows in the view. The default value is \c
+false.
+
+\note If this property is set, the VerticalHeaderView allows the user to drag
+and drop rows at the required position. When syncView is enabled,
+any change will be applied to the corresponding view item.
+//! [movableRows]
diff --git a/src/quickcontrols/doc/src/includes/qquickmenu.qdocinc b/src/quickcontrols/doc/src/includes/qquickmenu.qdocinc
new file mode 100644
index 0000000000..86a65338e5
--- /dev/null
+++ b/src/quickcontrols/doc/src/includes/qquickmenu.qdocinc
@@ -0,0 +1,4 @@
+//! [non-native-only-property]
+\note This property is only supported when using a
+\l {Native Menus}{non-native Menu}.
+//! [non-native-only-property]
diff --git a/src/quickcontrols/doc/src/qtquickcontrols-customize.qdoc b/src/quickcontrols/doc/src/qtquickcontrols-customize.qdoc
index 5c93e43441..1f12b72822 100644
--- a/src/quickcontrols/doc/src/qtquickcontrols-customize.qdoc
+++ b/src/quickcontrols/doc/src/qtquickcontrols-customize.qdoc
@@ -557,7 +557,7 @@
\code
import QtQuick
- import QtQuick.Controls
+ import QtQuick.Controls.Basic
ApplicationWindow {
visible: true
@@ -728,7 +728,7 @@
\quotefromfile qtquickcontrols-menu-custom.qml
\skipto import QtQuick
- \printuntil import QtQuick.Controls
+ \printuntil import QtQuick.Controls.Basic
\skipto Menu
\printto eof
@@ -743,7 +743,7 @@
\quotefromfile qtquickcontrols-menubar-custom.qml
\skipto import QtQuick
- \printuntil import QtQuick.Controls
+ \printuntil import QtQuick.Controls.Basic
\skipto MenuBar
\printto eof
@@ -775,7 +775,7 @@
\quotefromfile qtquickcontrols-popup-custom.qml
\skipto import QtQuick
- \printuntil import QtQuick.Controls
+ \printuntil import QtQuick.Controls.Basic
\codeline
\skipto Popup
\printuntil {
@@ -1013,7 +1013,7 @@
\quotefromfile qtquickcontrols-tooltip-custom.qml
\skipto import QtQuick
- \printuntil import QtQuick.Controls
+ \printuntil import QtQuick.Controls.Basic
\skipto ToolTip
\printuntil }
\printuntil }
diff --git a/src/quickcontrols/doc/src/qtquickcontrols-fusion.qdoc b/src/quickcontrols/doc/src/qtquickcontrols-fusion.qdoc
index 05792fb7da..a2db843039 100644
--- a/src/quickcontrols/doc/src/qtquickcontrols-fusion.qdoc
+++ b/src/quickcontrols/doc/src/qtquickcontrols-fusion.qdoc
@@ -11,6 +11,10 @@
look and feel. It implements the same design language as the
\l {Qt Widget Gallery}{Fusion style for Qt Widgets}.
+ The Fusion style automatically switches dark and light themes according to
+ the system settings. For information on how to set custom theme colors,
+ refer to the \l {customize-fusion-style}{Customization} section.
+
\include style-screenshots.qdocinc {file} {Fusion} {fusion}
To run an application with the Fusion style, see
@@ -22,17 +26,18 @@
rendering engines.
\section2 Customization
+ \target customize-fusion-style
The Fusion style uses the standard system \l[QtQuick]{Palette}
to provide colors that match the desktop environment.
\image qtquickcontrols-fusion-palettes.png
- Custom palettes can be specified for any control,
- \l{Popup::palette}{popup}, or \l{Window::palette}{application window}.
- Explicit palette attributes are automatically propagated from parent to children,
- overriding any system defaults for that attribute. In the following example,
- the window and all three switches appear with a violet highlight color:
+ You can specify custom palettes for any control, \l{Popup::palette}{popup},
+ or \l{Window::palette}{application window}. Explicit palette attributes are
+ automatically propagated from parent to children, overriding any system
+ defaults for that attribute. In the following example, the window and all
+ three switches appear with a violet highlight color:
\table
\row
diff --git a/src/quickcontrols/doc/src/qtquickcontrols-styles.qdoc b/src/quickcontrols/doc/src/qtquickcontrols-styles.qdoc
index 037ca15081..38174ab09a 100644
--- a/src/quickcontrols/doc/src/qtquickcontrols-styles.qdoc
+++ b/src/quickcontrols/doc/src/qtquickcontrols-styles.qdoc
@@ -131,20 +131,34 @@
import QtQuick.Controls
\endqml
- The QtQuick.Controls plugin will import the style and fallback
- style that were set at runtime via one of the following approaches:
+ The QtQuick.Controls plugin will import the style that was set at runtime
+ via one of the following approaches:
\list
\li \l[CPP]{QQuickStyle::setStyle()}
\li The \c -style command line argument
- \li The \c QT_QUICK_CONTROLS_STYLE environment variable
- \li The \c qtquickcontrols2.conf configuration file
+ \li The \l {Supported Environment Variables in Qt Quick Controls}
+ {QT_QUICK_CONTROLS_STYLE environment variable}
+ \li The \l {Qt Quick Controls Configuration File}{qtquickcontrols2.conf
+ configuration file}
\endlist
The priority of these approaches follows the order they are listed,
from highest to lowest. That is, using \c QQuickStyle to set the style will
always take priority over using the command line argument, for example.
+ Similarly, the fallback style can be set via one of the following methods:
+ \list
+ \li \l[CPP]{QQuickStyle::setFallbackStyle()}
+ \li The \l {Supported Environment Variables in Qt Quick Controls}
+ {QT_QUICK_CONTROLS_FALLBACK_STYLE environment variable}
+ \li The \l {Qt Quick Controls Configuration File}{qtquickcontrols2.conf
+ configuration file}
+ \endlist
+
+ \note you can only dynamically choose the fallback style if it hasn't been
+ chosen statically in the main style's qmldir file.
+
The benefit of run-time style selection is that a single application binary
can support multiple styles, meaning that the end user can choose which
style to run the application with.
diff --git a/src/quickcontrols/fluentwinui3/ApplicationWindow.qml b/src/quickcontrols/fluentwinui3/ApplicationWindow.qml
new file mode 100644
index 0000000000..2ed493f7bb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/ApplicationWindow.qml
@@ -0,0 +1,12 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ApplicationWindow {
+ id: window
+
+ color: window.palette.window
+}
diff --git a/src/quickcontrols/fluentwinui3/Button.qml b/src/quickcontrols/fluentwinui3/Button.qml
new file mode 100644
index 0000000000..a1b801714b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/Button.qml
@@ -0,0 +1,59 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Button {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ icon.width: 16
+ icon.height: 16
+ icon.color: (control.checked || control.highlighted)
+ ? (control.down ? (Application.styleHints.colorScheme == Qt.Light ? "#7FFFFFFF" : "#80000000") //textOnAccentSecondary
+ : control.palette.highlightedText)
+ : (control.down ? control.palette.brightText : control.palette.buttonText)
+
+ readonly property string __currentState: [
+ (control.checked || control.highlighted) && "checked",
+ !control.enabled && "disabled",
+ control.enabled && !control.down && control.hovered && "hovered",
+ control.down && "pressed"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: (control.flat && Config.controls.flatbutton
+ ? Config.controls.flatbutton[__currentState]
+ : Config.controls.button[__currentState]) || {}
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.config.label.textVAlignment | control.config.label.textHAlignment
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.icon.color
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/CMakeLists.txt b/src/quickcontrols/fluentwinui3/CMakeLists.txt
new file mode 100644
index 0000000000..28e7b8332c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/CMakeLists.txt
@@ -0,0 +1,79 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## qtquickcontrols2fluentwinui3styleplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "ApplicationWindow.qml"
+ "Button.qml"
+ "CheckBox.qml"
+ "ComboBox.qml"
+ "Frame.qml"
+ "GroupBox.qml"
+ "ItemDelegate.qml"
+ "Popup.qml"
+ "ProgressBar.qml"
+ "RadioButton.qml"
+ "RangeSlider.qml"
+ "Slider.qml"
+ "SpinBox.qml"
+ "Switch.qml"
+ "TabBar.qml"
+ "TabButton.qml"
+ "TextField.qml"
+ "TextArea.qml"
+ "ToolBar.qml"
+ "ToolButton.qml"
+ "Config.qml" # TODO: move to impl module
+ "StyleImage.qml" # TODO: move to impl module
+)
+
+set_source_files_properties(Config.qml PROPERTIES
+ QT_QML_SINGLETON_TYPE TRUE
+)
+
+file(GLOB light_theme_resources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "light/images/*.png")
+file(GLOB dark_theme_resources RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "dark/images/*.png")
+
+add_subdirectory(impl)
+
+qt_internal_add_qml_module(qtquickcontrols2fluentwinui3styleplugin
+ URI "QtQuick.Controls.FluentWinUI3"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ CLASS_NAME QtQuickControls2FluentWinUI3StylePlugin
+ IMPORTS
+ QtQuick.Controls.Fusion/auto
+ PLUGIN_TARGET qtquickcontrols2fluentwinui3styleplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ qtquickcontrols2fluentwinui3styleplugin.cpp
+ qquickfluentwinui3theme_p.h qquickfluentwinui3theme.cpp
+ QML_FILES
+ ${qml_files}
+ RESOURCES
+ ${light_theme_resources}
+ ${dark_theme_resources}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2FluentWinUI3StyleImpl
+ Qt::QuickControls2ImplPrivate
+ Qt::QuickControls2Private
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
+
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2fluentwinui3styleplugin
+ qtquickcontrols2fluentwinui3styleimplplugin)
+
+# Fusion style is the required fallback style.
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2fluentwinui3styleplugin
+ qtquickcontrols2fusionstyleplugin)
diff --git a/src/quickcontrols/fluentwinui3/CheckBox.qml b/src/quickcontrols/fluentwinui3/CheckBox.qml
new file mode 100644
index 0000000000..52d7efde42
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/CheckBox.qml
@@ -0,0 +1,61 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.CheckBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: [
+ control.checkState === Qt.Checked && "checked",
+ !control.enabled && "disabled",
+ control.enabled && !control.down && control.hovered && "hovered",
+ control.checkState === Qt.PartiallyChecked && "partiallyChecked",
+ control.down && "pressed",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.checkbox[__currentState] || {}
+ readonly property bool mirroredIndicator: control.mirrored !== (config.mirrored || false)
+
+ // TODO: Add animation for indicator
+ indicator: Image {
+ x: control.text ? (control.mirroredIndicator ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ source: Qt.resolvedUrl(control.config.indicator.filePath)
+ }
+
+ contentItem: Text {
+ leftPadding: control.indicator && !control.mirroredIndicator ? control.indicator.width + control.spacing : 0
+ rightPadding: control.indicator && control.mirroredIndicator ? control.indicator.width + control.spacing : 0
+
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/ComboBox.qml b/src/quickcontrols/fluentwinui3/ComboBox.qml
new file mode 100644
index 0000000000..fafe4c68f5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/ComboBox.qml
@@ -0,0 +1,138 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+pragma ComponentBehavior: Bound
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.FluentWinUI3.impl
+
+T.ComboBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: config.contentItem.spacing || 0
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: (config.leftPadding + (!control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)) || 0
+ rightPadding: (config.rightPadding + (control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)) || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: [
+ !control.enabled && "disabled",
+ control.enabled && !control.pressed && control.hovered && "hovered",
+ control.down && control.popup.visible && "open",
+ control.pressed && "pressed"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: (control.editable && control.down && control.popup.visible // editable combobox differs from normal one only in opened state
+ ? Config.controls.editablecombobox[__currentState]
+ : Config.controls.combobox[__currentState]) || {}
+
+ delegate: ItemDelegate {
+ required property var model
+ required property int index
+
+ width: ListView.view.width
+ text: model[control.textRole]
+ palette.highlightedText: control.palette.highlightedText
+ highlighted: control.highlightedIndex === index
+ hoverEnabled: control.hoverEnabled
+ }
+
+ indicator: Image {
+ x: control.mirrored ? control.config.leftPadding : control.width - width - control.config.rightPadding
+ y: (control.topPadding + (control.availableHeight - height) / 2) + (control.pressed ? 1 : 0)
+ source: Qt.resolvedUrl(control.config.indicator.filePath)
+
+ Behavior on y {
+ NumberAnimation{ easing.type: Easing.OutCubic; duration: 167 }
+ }
+ }
+
+ contentItem: T.TextField {
+ text: control.editable ? control.editText : control.displayText
+
+ topPadding: control.config.label_contentItem.topPadding || 0
+ leftPadding: control.config.label_contentItem.leftPadding || 0
+ rightPadding: control.config.label_contentItem.rightPadding || 0
+ bottomPadding: control.config.label_contentItem.bottomPadding || 0
+
+ implicitWidth: (implicitBackgroundWidth + leftInset + rightInset)
+ || contentWidth + leftPadding + rightPadding
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ enabled: control.editable
+ autoScroll: control.editable
+ readOnly: control.down
+ inputMethodHints: control.inputMethodHints
+ validator: control.validator
+ selectByMouse: control.selectTextByMouse
+
+ color: control.down ? control.palette.brightText : control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ horizontalAlignment: control.config.label_text.textHAlignment
+ verticalAlignment: control.config.label_text.textVAlignment
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ Item {
+ visible: control.editable && (control.down && control.popup.visible)
+ width: parent.width
+ height: 2
+ y: parent.height - height
+ FocusStroke {
+ width: parent.width
+ height: parent.height
+ radius: control.down && control.popup.visible ? 0 : control.config.background.bottomOffset
+ color: control.palette.accent
+ }
+ }
+ }
+
+ popup: T.Popup {
+ topPadding: control.config.popup_contentItem.topPadding || 0
+ leftPadding: control.config.popup_contentItem.leftPadding || 0
+ rightPadding: control.config.popup_contentItem.rightPadding || 0
+ bottomPadding: control.config.popup_contentItem.bottomPadding || 0
+
+ contentItem: ListView {
+ clip: true
+ implicitHeight: contentHeight
+ highlightMoveDuration: 0
+
+ model: control.delegateModel
+ currentIndex: control.highlightedIndex
+ }
+
+ y: control.editable ? control.height
+ : -0.25 * Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+ height: Math.min(contentItem.implicitHeight + topPadding + bottomPadding, control.Window.height - topMargin - bottomMargin)
+ width: control.width
+ topMargin: 8
+ bottomMargin: 8
+ palette: control.palette
+
+ enter: Transition {
+ NumberAnimation { property: "height"; from: control.popup.height / 3; to: control.popup.height; easing.type: Easing.OutCubic; duration: 250 }
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.popup_background.filePath ? control.config.popup_background : Config.controls.popup["normal"].background // fallback to regular popup
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/Config.qml b/src/quickcontrols/fluentwinui3/Config.qml
new file mode 100644
index 0000000000..7971917bc1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/Config.qml
@@ -0,0 +1,20664 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+pragma Singleton
+import QtQuick
+
+QtObject {
+ readonly property QtObject controls: Application.styleHints.colorScheme === Qt.Light ? light.controls : dark.controls
+
+ readonly property QtObject dark: QtObject {
+ readonly property QtObject controls: QtObject {
+ readonly property QtObject button: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17023;8603:12521;2373:10903"
+ readonly property string filePath: "dark/images/button-background-checked.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 1874
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17023;8603:12521"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17023;8603:12521;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 1882
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17023;8603:12521;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 1880
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17029;8603:12527;2373:10903"
+ readonly property string filePath: "dark/images/button-background-checked-disabled.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2075
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17029;8603:12527"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17029;8603:12527;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2083
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17029;8603:12527;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2081
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17027;8603:12525;2373:10903"
+ readonly property string filePath: "dark/images/button-background-checked-hovered.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2008
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17027;8603:12525"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17027;8603:12525;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2016
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17027;8603:12525;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2014
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17031;8603:12529;2373:10903"
+ readonly property string filePath: "dark/images/button-background-checked-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2142
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17031;8603:12529"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17031;8603:12529;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2150
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17031;8603:12529;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2148
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17025;8603:12523;2373:10903"
+ readonly property string filePath: "dark/images/button-background-disabled.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 1941
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17025;8603:12523"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17025;8603:12523;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 1949
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17025;8603:12523;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 1947
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17019;8603:12517;2373:10903"
+ readonly property string filePath: "dark/images/button-background-hovered.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 1740
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17019;8603:12517"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17019;8603:12517;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 1748
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17019;8603:12517;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 1746
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17017;8603:12515;2373:10903"
+ readonly property string filePath: "dark/images/button-background.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2227.5
+ readonly property real y: 1686
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17017;8603:12515"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17017;8603:12515;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2247.5
+ readonly property real y: 1694
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17017;8603:12515;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2271.5
+ readonly property real y: 1692
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17021;8603:12519;2373:10903"
+ readonly property string filePath: "dark/images/button-background-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 1807
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17021;8603:12519"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17021;8603:12519;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 1815
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17021;8603:12519;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 1813
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject checkbox: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17040;8622:13107;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2838.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:17040;8622:13107"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17040;8622:13107;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-checked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2843.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17040;8622:13107;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2843.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17050;8622:13117;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 3114.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:17050;8622:13117"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17050;8622:13117;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-checked-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 3119.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17050;8622:13117;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 3119.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17054;8622:13121;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2976.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:17054;8622:13121"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17054;8622:13121;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-checked-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2981.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17054;8622:13121;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2981.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17052;8622:13119;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 3045.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:17052;8622:13119"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17052;8622:13119;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-checked-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 3050.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17052;8622:13119;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 3050.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17056;8622:13123;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2907.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:17056;8622:13123"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17056;8622:13123;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2912.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17056;8622:13123;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2912.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled_partiallyChecked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17048;8622:13115;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-disabled-partiallyChecked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 3390.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:17048;8622:13115"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-disabled-partiallyChecked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17048;8622:13115;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-disabled-partiallyChecked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-disabled-partiallyChecked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 3395.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17048;8622:13115;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-disabled-partiallyChecked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 3395.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17036;8622:13103;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2700.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:17036;8622:13103"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17036;8622:13103;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2705.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17036;8622:13103;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2705.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered_partiallyChecked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17044;8622:13111;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-hovered-partiallyChecked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 3252.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:17044;8622:13111"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-hovered-partiallyChecked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17044;8622:13111;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-hovered-partiallyChecked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-hovered-partiallyChecked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 3257.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17044;8622:13111;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-hovered-partiallyChecked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 3257.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17034;8622:13101;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2631.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:17034;8622:13101"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17034;8622:13101;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2636.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17034;8622:13101;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2636.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject partiallyChecked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17042;8622:13109;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-partiallyChecked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 3183.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:17042;8622:13109"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-partiallyChecked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17042;8622:13109;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-partiallyChecked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-partiallyChecked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 3188.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17042;8622:13109;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-partiallyChecked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 3188.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject partiallyChecked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17046;8622:13113;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-partiallyChecked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 3321.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:17046;8622:13113"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-partiallyChecked-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17046;8622:13113;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-partiallyChecked-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-partiallyChecked-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 3326.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17046;8622:13113;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-partiallyChecked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 3326.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17038;8622:13105;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2769.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:17038;8622:13105"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17038;8622:13105;2425:10953"
+ readonly property string filePath: "dark/images/checkbox-indicator-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2774.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17038;8622:13105;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2774.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject combobox: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17071;2407:10440;2397:10728"
+ readonly property string filePath: "dark/images/combobox-background-disabled.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8122
+ readonly property real y: 4817
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17071;2407:10440"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17071;2407:10440;2397:10731"
+ readonly property string filePath: "dark/images/combobox-indicator-disabled.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8219
+ readonly property real y: 4825
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17071;2407:10440;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 8135
+ readonly property real y: 4823
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:17071;2407:10440;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-disabled"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:17071;2407:10440;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-disabled"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17071;2407:10440;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-disabled"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8122
+ readonly property real y: 4849
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17071;2407:10440;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-disabled"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject focused: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4677:11470;4606:28948;2397:10728"
+ readonly property string filePath: "dark/images/combobox-background-focused.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-focused"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8122
+ readonly property real y: 4884
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4677:11470;4606:28948"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-focused"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4677:11470;4606:28948;2397:10731"
+ readonly property string filePath: "dark/images/combobox-indicator-focused.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-focused"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8219
+ readonly property real y: 4892
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4677:11470;4606:28948;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-focused"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 8135
+ readonly property real y: 4890
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4677:11470;4606:28948;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-focused"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4677:11470;4606:28948;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-focused"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4677:11470;4606:28948;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-focused"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8122
+ readonly property real y: 4916
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4677:11470;4606:28948;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-focused"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17061;2397:10784;2397:10728"
+ readonly property string filePath: "dark/images/combobox-background-hovered.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8098.5
+ readonly property real y: 3996
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17061;2397:10784"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17061;2397:10784;2397:10731"
+ readonly property string filePath: "dark/images/combobox-indicator-hovered.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8195.5
+ readonly property real y: 4004
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17061;2397:10784;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 8111.5
+ readonly property real y: 4002
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:17061;2397:10784;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-hovered"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:17061;2397:10784;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-hovered"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17061;2397:10784;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-hovered"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8098.5
+ readonly property real y: 4028
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17061;2397:10784;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-hovered"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered_open: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17067;2407:10424;2397:10728"
+ readonly property string filePath: "dark/images/combobox-background-hovered-open.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-hovered-open"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8122
+ readonly property real y: 4359
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17067;2407:10424"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-hovered-open"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17067;2407:10424;2397:10731"
+ readonly property string filePath: "dark/images/combobox-indicator-hovered-open.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-hovered-open"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8219
+ readonly property real y: 4367
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17067;2407:10424;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-hovered-open"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 8135
+ readonly property real y: 4365
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:17067;2407:10424;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-hovered-open"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:17067;2407:10424;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-hovered-open"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17067;2407:10424;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-hovered-open"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8122
+ readonly property real y: 4391
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17067;2407:10424;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-hovered-open"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17059;2397:10736;2397:10728"
+ readonly property string filePath: "dark/images/combobox-background.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8098.5
+ readonly property real y: 3929
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17059;2397:10736"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17059;2397:10736;2397:10731"
+ readonly property string filePath: "dark/images/combobox-indicator.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8195.5
+ readonly property real y: 3937
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17059;2397:10736;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 8111.5
+ readonly property real y: 3935
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:17059;2397:10736;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:17059;2397:10736;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17059;2397:10736;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8098.5
+ readonly property real y: 3961
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17059;2397:10736;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject open: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17065;2399:10706;2397:10728"
+ readonly property string filePath: "dark/images/combobox-background-open.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-open"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8122
+ readonly property real y: 4130
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17065;2399:10706"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-open"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17065;2399:10706;2397:10731"
+ readonly property string filePath: "dark/images/combobox-indicator-open.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-open"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8219
+ readonly property real y: 4138
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17065;2399:10706;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-open"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 8135
+ readonly property real y: 4136
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:17065;2399:10706;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-open"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:17065;2399:10706;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-open"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17065;2399:10706;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-open"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8122
+ readonly property real y: 4162
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17065;2399:10706;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-open"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject open_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17069;2407:10432;2397:10728"
+ readonly property string filePath: "dark/images/combobox-background-open-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-open-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8122
+ readonly property real y: 4585
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17069;2407:10432"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-open-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17069;2407:10432;2397:10731"
+ readonly property string filePath: "dark/images/combobox-indicator-open-pressed.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-open-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8219
+ readonly property real y: 4593
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17069;2407:10432;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-open-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 8135
+ readonly property real y: 4591
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:17069;2407:10432;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-open-pressed"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:17069;2407:10432;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-open-pressed"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17069;2407:10432;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-open-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8122
+ readonly property real y: 4617
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17069;2407:10432;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-open-pressed"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17063;2397:10792;2397:10728"
+ readonly property string filePath: "dark/images/combobox-background-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8122
+ readonly property real y: 4063
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17063;2397:10792"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17063;2397:10792;2397:10731"
+ readonly property string filePath: "dark/images/combobox-indicator-pressed.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8219
+ readonly property real y: 4071
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17063;2397:10792;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 8135
+ readonly property real y: 4069
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:17063;2397:10792;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-pressed"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:17063;2397:10792;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-pressed"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17063;2397:10792;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8122
+ readonly property real y: 4095
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17063;2397:10792;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-pressed"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject editablecombobox: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9461;4610:29709;4610:29350"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-disabled"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8858
+ readonly property real y: 4817.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9461;4610:29709"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9461;4610:29709;4610:29356"
+ readonly property string filePath: ""
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8954
+ readonly property real y: 4825
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9461;4610:29709;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8872
+ readonly property real y: 4822
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9461;4610:29709;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-disabled"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9461;4610:29709;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-disabled"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9461;4610:29709;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-popup-background-disabled"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8859
+ readonly property real y: 4848.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9461;4610:29709;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-disabled"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject focused: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4677:11669;4610:29759;4610:29350"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-focused"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8858
+ readonly property real y: 4884.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4677:11669;4610:29759"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-focused"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4677:11669;4610:29759;4610:29356"
+ readonly property string filePath: ""
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-focused"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8954
+ readonly property real y: 4892
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4677:11669;4610:29759;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-focused"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8872
+ readonly property real y: 4889
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4677:11669;4610:29759;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-focused"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4677:11669;4610:29759;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-focused"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4677:11669;4610:29759;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-popup-background-focused"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8859
+ readonly property real y: 4915.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4677:11669;4610:29759;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-focused"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9451;4610:29459;4610:29350"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-hovered"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8858
+ readonly property real y: 3996.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9451;4610:29459"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9451;4610:29459;4610:29356"
+ readonly property string filePath: ""
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8954
+ readonly property real y: 4004
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9451;4610:29459;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8872
+ readonly property real y: 4001
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9451;4610:29459;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-hovered"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9451;4610:29459;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-hovered"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9451;4610:29459;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-popup-background-hovered"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8859
+ readonly property real y: 4027.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9451;4610:29459;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-hovered"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered_open: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9457;4610:29609;4610:29350"
+ readonly property string filePath: "dark/images/editablecombobox-background-hovered-open.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-hovered-open"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8858
+ readonly property real y: 4359.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9457;4610:29609"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-hovered-open"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9457;4610:29609;4610:29356"
+ readonly property string filePath: "dark/images/editablecombobox-indicator-hovered-open.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-hovered-open"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8954
+ readonly property real y: 4367
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9457;4610:29609;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-hovered-open"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8872
+ readonly property real y: 4364
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9457;4610:29609;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-hovered-open"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9457;4610:29609;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-hovered-open"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 8
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9457;4610:29609;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: "dark/images/editablecombobox-popup-background-hovered-open.png"
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 4
+ readonly property string name: "editablecombobox-popup-background-hovered-open"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 4
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8859
+ readonly property real y: 4390.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9457;4610:29609;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-hovered-open"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9449;4610:29409;4610:29350"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8858
+ readonly property real y: 3929.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9449;4610:29409"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9449;4610:29409;4610:29356"
+ readonly property string filePath: ""
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8954
+ readonly property real y: 3937
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9449;4610:29409;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8872
+ readonly property real y: 3934
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9449;4610:29409;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9449;4610:29409;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9449;4610:29409;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-popup-background"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8859
+ readonly property real y: 3960.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9449;4610:29409;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject open: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9455;4610:29559;4610:29350"
+ readonly property string filePath: "dark/images/editablecombobox-background-open.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-open"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8858
+ readonly property real y: 4130.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9455;4610:29559"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-open"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9455;4610:29559;4610:29356"
+ readonly property string filePath: "dark/images/editablecombobox-indicator-open.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-open"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8954
+ readonly property real y: 4138
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9455;4610:29559;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-open"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8872
+ readonly property real y: 4135
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9455;4610:29559;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-open"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9455;4610:29559;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-open"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 8
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9455;4610:29559;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: "dark/images/editablecombobox-popup-background-open.png"
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 4
+ readonly property string name: "editablecombobox-popup-background-open"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 4
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8859
+ readonly property real y: 4161.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9455;4610:29559;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-open"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject open_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9459;4610:29659;4610:29350"
+ readonly property string filePath: "dark/images/editablecombobox-background-open-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-open-pressed"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8858
+ readonly property real y: 4585.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9459;4610:29659"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-open-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9459;4610:29659;4610:29356"
+ readonly property string filePath: "dark/images/editablecombobox-indicator-open-pressed.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-open-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8954
+ readonly property real y: 4593
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9459;4610:29659;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-open-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8872
+ readonly property real y: 4590
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9459;4610:29659;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-open-pressed"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9459;4610:29659;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-open-pressed"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 8
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9459;4610:29659;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: "dark/images/editablecombobox-popup-background-open-pressed.png"
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 4
+ readonly property string name: "editablecombobox-popup-background-open-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 4
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8859
+ readonly property real y: 4616.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9459;4610:29659;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-open-pressed"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9453;4610:29509;4610:29350"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-pressed"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8858
+ readonly property real y: 4063.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9453;4610:29509"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9453;4610:29509;4610:29356"
+ readonly property string filePath: ""
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8954
+ readonly property real y: 4071
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9453;4610:29509;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8872
+ readonly property real y: 4068
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9453;4610:29509;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-pressed"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9453;4610:29509;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-pressed"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9453;4610:29509;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-popup-background-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8859
+ readonly property real y: 4094.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9453;4610:29509;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-pressed"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject flatbutton: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9227;3987:9104;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-checked.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 2039.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9227;3987:9104"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9227;3987:9104;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 2045.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9227;3987:9104;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 2045.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9230;3987:9122;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-checked-disabled.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked-disabled"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 2173.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9230;3987:9122"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9230;3987:9122;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 2179.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9230;3987:9122;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 2179.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9229;3987:9113;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-checked-hovered.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked-hovered"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 2106.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9229;3987:9113"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9229;3987:9113;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 2112.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9229;3987:9113;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 2112.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9231;3987:9131;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-checked-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked-pressed"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 2240.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9231;3987:9131"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9231;3987:9131;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 2246.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9231;3987:9131;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 2246.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9228;3987:9095;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-disabled.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-disabled"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 1972.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9228;3987:9095"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9228;3987:9095;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 1978.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9228;3987:9095;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 1978.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9225;3987:9077;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-hovered.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-hovered"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 1838.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9225;3987:9077"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9225;3987:9077;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 1844.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9225;3987:9077;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 1844.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9224;3987:9068;3987:9044"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 1771.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9224;3987:9068"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9224;3987:9068;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 1777.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9224;3987:9068;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 1777.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9226;3987:9086;3987:9044"
+ readonly property string filePath: "dark/images/flatbutton-background-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-pressed"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3315.5
+ readonly property real y: 1905.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9226;3987:9086"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9226;3987:9086;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3332.5
+ readonly property real y: 1911.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9226;3987:9086;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3360.5
+ readonly property real y: 1911.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject frame: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17105;2439:15806;2439:15811"
+ readonly property string filePath: "dark/images/frame-background-disabled.png"
+ readonly property real height: 52
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "frame-background-disabled"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 65
+ readonly property real x: 11761.5
+ readonly property real y: 3009
+ }
+
+ readonly property real bottomPadding: 16
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 16
+ readonly property string figmaId: "I2557:17105;2439:15806"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 16
+ readonly property string name: "frame-contentItem-disabled"
+ readonly property real rightPadding: 16
+ readonly property real spacing: 0
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17105;2439:15806;2439:15788"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "frame-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 11777.5
+ readonly property real y: 3025
+ }
+
+ readonly property real leftPadding: 16
+ readonly property real rightPadding: 16
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17103;2439:15801;2439:15811"
+ readonly property string filePath: "dark/images/frame-background.png"
+ readonly property real height: 52
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "frame-background"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 65
+ readonly property real x: 11761.5
+ readonly property real y: 2797
+ }
+
+ readonly property real bottomPadding: 16
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 16
+ readonly property string figmaId: "I2557:17103;2439:15801"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 16
+ readonly property string name: "frame-contentItem"
+ readonly property real rightPadding: 16
+ readonly property real spacing: 0
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17103;2439:15801;2439:15788"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "frame-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 11777.5
+ readonly property real y: 2813
+ }
+
+ readonly property real leftPadding: 16
+ readonly property real rightPadding: 16
+ readonly property real topPadding: 16
+ }
+
+ }
+
+ readonly property QtObject groupbox: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17233;2556:14470;2554:14173"
+ readonly property string filePath: ""
+ readonly property real height: 52
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-background-disabled"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 13007.5
+ readonly property real y: 3721
+ }
+
+ readonly property real bottomPadding: 16
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 16
+ readonly property string figmaId: "I2557:17233;2556:14470;4176:22635"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 16
+ readonly property string name: "groupbox-contentItem-disabled"
+ readonly property real rightPadding: 16
+ readonly property real spacing: 0
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17233;2556:14470;4330:10056"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 13007.5
+ readonly property real y: 3693
+ }
+
+ readonly property QtObject label_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17233;2556:14470;4330:10056;4330:10044"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-label-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 13007.5
+ readonly property real y: 3693
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:17233;2556:14470;4330:10056"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "groupbox-label-contentItem-disabled"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:17233;2556:14470;4330:10056;4330:9505"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "groupbox-label-text-disabled"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 16
+ readonly property real rightPadding: 16
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17231;2556:14430;2554:14173"
+ readonly property string filePath: ""
+ readonly property real height: 52
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-background-hovered"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 13007.5
+ readonly property real y: 3508
+ }
+
+ readonly property real bottomPadding: 16
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 16
+ readonly property string figmaId: "I2557:17231;2556:14430;4176:22635"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 16
+ readonly property string name: "groupbox-contentItem-hovered"
+ readonly property real rightPadding: 16
+ readonly property real spacing: 0
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17231;2556:14430;4330:10056"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 13007.5
+ readonly property real y: 3480
+ }
+
+ readonly property QtObject label_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17231;2556:14430;4330:10056;4330:10044"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-label-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 13007.5
+ readonly property real y: 3480
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:17231;2556:14430;4330:10056"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "groupbox-label-contentItem-hovered"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:17231;2556:14430;4330:10056;4330:9505"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "groupbox-label-text-hovered"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 16
+ readonly property real rightPadding: 16
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17229;2556:14390;2554:14173"
+ readonly property string filePath: ""
+ readonly property real height: 52
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-background"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 13007
+ readonly property real y: 3296
+ }
+
+ readonly property real bottomPadding: 16
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 16
+ readonly property string figmaId: "I2557:17229;2556:14390;4176:22635"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 16
+ readonly property string name: "groupbox-contentItem"
+ readonly property real rightPadding: 16
+ readonly property real spacing: 0
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17229;2556:14390;4330:10056"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-label"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 13007
+ readonly property real y: 3268
+ }
+
+ readonly property QtObject label_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17229;2556:14390;4330:10056;4330:10044"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-label-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 13007
+ readonly property real y: 3268
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:17229;2556:14390;4330:10056"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "groupbox-label-contentItem"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:17229;2556:14390;4330:10056;4330:9505"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "groupbox-label-text"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 16
+ readonly property real rightPadding: 16
+ readonly property real topPadding: 16
+ }
+
+ }
+
+ readonly property QtObject itemdelegate: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17085;2319:9946;2399:11597"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5917
+ readonly property real y: 2010.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:17085;2319:9946"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17085;2319:9946;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5924.5
+ readonly property real y: 2018.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject highlighted: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17087;2319:9952;2399:11597"
+ readonly property string filePath: "dark/images/itemdelegate-background-highlighted.png"
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background-highlighted"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5917
+ readonly property real y: 2077.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:17087;2319:9952"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem-highlighted"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17087;2319:9952;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label-highlighted"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5924.5
+ readonly property real y: 2085.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject highlighted_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17089;2319:9958;2399:11597"
+ readonly property string filePath: "dark/images/itemdelegate-background-highlighted-hovered.png"
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background-highlighted-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5917
+ readonly property real y: 2137.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:17089;2319:9958"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem-highlighted-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17089;2319:9958;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label-highlighted-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5924.5
+ readonly property real y: 2145.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject highlighted_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17091;2319:9970;2399:11597"
+ readonly property string filePath: "dark/images/itemdelegate-background-highlighted-pressed.png"
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background-highlighted-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5917
+ readonly property real y: 2211.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:17091;2319:9970"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem-highlighted-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17091;2319:9970;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label-highlighted-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5924.5
+ readonly property real y: 2219.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17081;2319:9922;2399:11597"
+ readonly property string filePath: "dark/images/itemdelegate-background-hovered.png"
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5917
+ readonly property real y: 1876.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:17081;2319:9922"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17081;2319:9922;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5924.5
+ readonly property real y: 1884.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17079;2319:9916;2399:11597"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5917
+ readonly property real y: 1809.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:17079;2319:9916"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17079;2319:9916;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5924.5
+ readonly property real y: 1817.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17083;2319:9934;2399:11597"
+ readonly property string filePath: "dark/images/itemdelegate-background-pressed.png"
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5917
+ readonly property real y: 1943.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:17083;2319:9934"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17083;2319:9934;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5924.5
+ readonly property real y: 1951.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ }
+
+ readonly property QtObject popup: QtObject {
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 24
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17074;2308:11133;2313:11247"
+ readonly property string filePath: "dark/images/popup-background.png"
+ readonly property real height: 106
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 16
+ readonly property string name: "popup-background"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 16
+ readonly property real topOffset: 8
+ readonly property real topShadow: 8
+ readonly property real width: 118
+ readonly property real x: 7147
+ readonly property real y: 2194
+ }
+
+ readonly property real bottomPadding: 16
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 16
+ readonly property string figmaId: "I2557:17074;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 16
+ readonly property string name: "popup-contentItem"
+ readonly property real rightPadding: 16
+ readonly property real spacing: 0
+ readonly property real topPadding: 16
+ }
+
+ readonly property real leftPadding: 16
+ readonly property real rightPadding: 16
+ readonly property real topPadding: 16
+ }
+
+ }
+
+ readonly property QtObject progressbar: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9378;4304:9328"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem-disabled"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9378;4304:9328;4413:23724"
+ readonly property string filePath: "dark/images/progressbar-groove-disabled.png"
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15842
+ readonly property real y: 2059
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9378;4304:9328;4267:14564"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15842
+ readonly property real y: 2058
+ }
+
+ }
+
+ readonly property QtObject disabled_indeterminate: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9380;4304:9355"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem-disabled-indeterminate"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9380;4304:9355;4350:35746"
+ readonly property string filePath: ""
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove-disabled-indeterminate"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15842
+ readonly property real y: 2132
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9380;4304:9355;4403:22724"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track-disabled-indeterminate"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15908
+ readonly property real y: 2131
+ }
+
+ }
+
+ readonly property QtObject indeterminate: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9376;2450:12847"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem-indeterminate"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9376;2450:12847;4350:35746"
+ readonly property string filePath: ""
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove-indeterminate"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15842
+ readonly property real y: 1986
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9376;2450:12847;4403:22724"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track-indeterminate"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15908
+ readonly property real y: 1985
+ }
+
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9374;2450:12841"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9374;2450:12841;4413:23724"
+ readonly property string filePath: "dark/images/progressbar-groove.png"
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15842
+ readonly property real y: 1913
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9374;2450:12841;4267:14564"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15842
+ readonly property real y: 1912
+ }
+
+ }
+
+ }
+
+ readonly property QtObject radiobutton: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17135;2483:15472;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 1977.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17135;2483:15472"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17135;2483:15472;2473:12871"
+ readonly property string filePath: "dark/images/radiobutton-indicator-checked.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 1983.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17135;2483:15472;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 1985.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17141;2488:15512;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 2255.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17141;2488:15512"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17141;2488:15512;2473:12871"
+ readonly property string filePath: "dark/images/radiobutton-indicator-checked-disabled.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 2261.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17141;2488:15512;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 2263.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17137;8622:14986"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 2119.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17137;8622:14985"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17137;8622:14996"
+ readonly property string filePath: "dark/images/radiobutton-indicator-checked-hovered.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 2125.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17137;8622:14988"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 2127.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17139;8622:15023"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 2186.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17139;8622:15022"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17139;8622:15033"
+ readonly property string filePath: "dark/images/radiobutton-indicator-checked-pressed.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 2192.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17139;8622:15025"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 2194.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17143;2483:15480;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 2048.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17143;2483:15480"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17143;2483:15480;2473:12871"
+ readonly property string filePath: "dark/images/radiobutton-indicator-disabled.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 2054.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17143;2483:15480;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 2056.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17131;2473:12899;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 1839.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17131;2473:12899"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17131;2473:12899;2473:12871"
+ readonly property string filePath: "dark/images/radiobutton-indicator-hovered.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 1845.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17131;2473:12899;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 1847.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17129;2473:12891;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 1770.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17129;2473:12891"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17129;2473:12891;2473:12871"
+ readonly property string filePath: "dark/images/radiobutton-indicator.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 1776.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17129;2473:12891;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 1778.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17133;8622:15060"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 17057.5
+ readonly property real y: 1908.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17133;8622:15059"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17133;8622:15070"
+ readonly property string filePath: "dark/images/radiobutton-indicator-pressed.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 17061.5
+ readonly property real y: 1914.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17133;8622:15062"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 17093.5
+ readonly property real y: 1916.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ }
+
+ readonly property QtObject rangeslider: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17152;2509:12481;2509:12419"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17964
+ readonly property real y: 2839
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17152;2509:12481"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17152;2509:12481;4189:38496"
+ readonly property string filePath: "dark/images/rangeslider-first-handle-disabled.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-first-handle-disabled"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 17991
+ readonly property real y: 2838
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17152;2509:12481;4178:28261"
+ readonly property string filePath: "dark/images/rangeslider-groove-disabled.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17972
+ readonly property real y: 2847
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17152;2509:12481;4191:43003"
+ readonly property string filePath: "dark/images/rangeslider-second-handle-disabled.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-second-handle-disabled"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 18115
+ readonly property real y: 2838
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17152;2509:12481;4189:38505"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 18002
+ readonly property real y: 2847
+ }
+
+ }
+
+ readonly property QtObject handle_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17150;8624:14526"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background-handle-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17964
+ readonly property real y: 2781
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17150;8624:14525"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem-handle-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17150;8624:14556"
+ readonly property string filePath: "dark/images/rangeslider-first-handle-handle-pressed.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-first-handle-handle-pressed"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 17991
+ readonly property real y: 2780
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17150;8624:14529"
+ readonly property string filePath: "dark/images/rangeslider-groove-handle-pressed.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove-handle-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17972
+ readonly property real y: 2789
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17150;8624:14627"
+ readonly property string filePath: "dark/images/rangeslider-second-handle-handle-pressed.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-second-handle-handle-pressed"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 18115
+ readonly property real y: 2780
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17150;8624:14531"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track-handle-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 18002
+ readonly property real y: 2789
+ }
+
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17148;8624:14397"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17964
+ readonly property real y: 2723
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17148;8624:14396"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17148;8624:14427"
+ readonly property string filePath: "dark/images/rangeslider-first-handle-hovered.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-first-handle-hovered"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 17991
+ readonly property real y: 2722
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17148;8624:14400"
+ readonly property string filePath: "dark/images/rangeslider-groove-hovered.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17972
+ readonly property real y: 2731
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17148;8624:14506"
+ readonly property string filePath: "dark/images/rangeslider-second-handle-hovered.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-second-handle-hovered"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 18115
+ readonly property real y: 2722
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17148;8624:14402"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 18002
+ readonly property real y: 2731
+ }
+
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17146;2509:12436;2509:12419"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17964
+ readonly property real y: 2665
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17146;2509:12436"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17146;2509:12436;4189:38496"
+ readonly property string filePath: "dark/images/rangeslider-first-handle.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-first-handle"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 17991
+ readonly property real y: 2664
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17146;2509:12436;4178:28261"
+ readonly property string filePath: "dark/images/rangeslider-groove.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17972
+ readonly property real y: 2673
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17146;2509:12436;4191:43003"
+ readonly property string filePath: "dark/images/rangeslider-second-handle.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-second-handle"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 18115
+ readonly property real y: 2664
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17146;2509:12436;4189:38505"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 18002
+ readonly property real y: 2673
+ }
+
+ }
+
+ }
+
+ readonly property QtObject slider: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17178;2506:12695;4200:48590"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22952
+ readonly property real y: 2827.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17178;2506:12695"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17178;2506:12695;4385:9106"
+ readonly property string filePath: "dark/images/slider-groove-disabled.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22960
+ readonly property real y: 2835.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17178;2506:12695;4200:48601"
+ readonly property string filePath: "dark/images/slider-handle-disabled.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-handle-disabled"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 23122
+ readonly property real y: 2826.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17178;2506:12695;4200:48597"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22960
+ readonly property real y: 2835.5
+ }
+
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17174;8624:13850"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22952
+ readonly property real y: 2708.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17174;8624:13849"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17174;8624:13853"
+ readonly property string filePath: "dark/images/slider-groove-hovered.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22960
+ readonly property real y: 2716.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17174;8624:13874"
+ readonly property string filePath: "dark/images/slider-handle-hovered.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-handle-hovered"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 23122
+ readonly property real y: 2707.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17174;8624:13855"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22960
+ readonly property real y: 2716.5
+ }
+
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17172;2506:12656;4200:48590"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22952
+ readonly property real y: 2649.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17172;2506:12656"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17172;2506:12656;4385:9106"
+ readonly property string filePath: "dark/images/slider-groove.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22960
+ readonly property real y: 2657.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17172;2506:12656;4200:48601"
+ readonly property string filePath: "dark/images/slider-handle.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-handle"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 23122
+ readonly property real y: 2648.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17172;2506:12656;4200:48597"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22960
+ readonly property real y: 2657.5
+ }
+
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17176;8624:14647"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22952
+ readonly property real y: 2768.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17176;8624:14646"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17176;8624:14650"
+ readonly property string filePath: "dark/images/slider-groove-pressed.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22960
+ readonly property real y: 2776.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17176;8624:14671"
+ readonly property string filePath: "dark/images/slider-handle-pressed.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-handle-pressed"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 23122
+ readonly property real y: 2767.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17176;8624:14652"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22960
+ readonly property real y: 2776.5
+ }
+
+ }
+
+ }
+
+ readonly property QtObject spinbox: QtObject {
+ readonly property QtObject atlimit: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17195;2766:9577;2526:13406"
+ readonly property string filePath: "dark/images/spinbox-background-atlimit.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-atlimit"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24589
+ readonly property real y: 2457.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17195;2766:9577"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-atlimit"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17195;2766:9577;2526:13408;4418:24767"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-background-atlimit.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-atlimit"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24681
+ readonly property real y: 2461.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17195;2766:9577;2526:13408;8858:14984"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-icon-atlimit.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-atlimit"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24692
+ readonly property real y: 2472.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17195;2766:9577;2526:13412;4418:25668"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-background-atlimit.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-atlimit"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24649
+ readonly property real y: 2461.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17195;2766:9577;2526:13412;8858:15141"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-icon-atlimit.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-atlimit"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24660
+ readonly property real y: 2472.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17195;2766:9577;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-atlimit"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24601
+ readonly property real y: 2464.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17185;2766:9207;2526:13406"
+ readonly property string filePath: "dark/images/spinbox-background-disabled.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24589
+ readonly property real y: 2122.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17185;2766:9207"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-disabled"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17185;2766:9207;2526:13408;4418:24767"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-background-disabled.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24681
+ readonly property real y: 2126.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17185;2766:9207;2526:13408;8858:14984"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-icon-disabled.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24692
+ readonly property real y: 2137.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17185;2766:9207;2526:13412;4418:25668"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-background-disabled.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24649
+ readonly property real y: 2126.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17185;2766:9207;2526:13412;8858:15141"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-icon-disabled.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24660
+ readonly property real y: 2137.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17185;2766:9207;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24601
+ readonly property real y: 2129.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject down_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17187;2766:9281;2526:13406"
+ readonly property string filePath: "dark/images/spinbox-background-down-hovered.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-down-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24589
+ readonly property real y: 2189.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17187;2766:9281"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-down-hovered"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17187;2766:9281;2526:13408;4418:24767"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-background-down-hovered.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-down-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24681
+ readonly property real y: 2193.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17187;2766:9281;2526:13408;8858:14984"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-icon-down-hovered.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-down-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24692
+ readonly property real y: 2204.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17187;2766:9281;2526:13412;4418:25668"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-background-down-hovered.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-down-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24649
+ readonly property real y: 2193.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17187;2766:9281;2526:13412;8858:15141"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-icon-down-hovered.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-down-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24660
+ readonly property real y: 2204.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17187;2766:9281;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-down-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24601
+ readonly property real y: 2196.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject down_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17189;2766:9355;2526:13406"
+ readonly property string filePath: "dark/images/spinbox-background-down-pressed.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-down-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24589
+ readonly property real y: 2256.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17189;2766:9355"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-down-pressed"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17189;2766:9355;2526:13408;4418:24767"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-background-down-pressed.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-down-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24681
+ readonly property real y: 2260.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17189;2766:9355;2526:13408;8858:14984"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-icon-down-pressed.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-down-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24692
+ readonly property real y: 2271.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17189;2766:9355;2526:13412;4418:25668"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-background-down-pressed.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-down-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24649
+ readonly property real y: 2260.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17189;2766:9355;2526:13412;8858:15141"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-icon-down-pressed.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-down-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24660
+ readonly property real y: 2271.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17189;2766:9355;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-down-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24601
+ readonly property real y: 2263.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17183;2766:9133;2526:13406"
+ readonly property string filePath: "dark/images/spinbox-background-hovered.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24589
+ readonly property real y: 2055.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17183;2766:9133"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-hovered"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17183;2766:9133;2526:13408;4418:24767"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-background-hovered.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24681
+ readonly property real y: 2059.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17183;2766:9133;2526:13408;8858:14984"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-icon-hovered.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24692
+ readonly property real y: 2070.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17183;2766:9133;2526:13412;4418:25668"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-background-hovered.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24649
+ readonly property real y: 2059.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17183;2766:9133;2526:13412;8858:15141"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-icon-hovered.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24660
+ readonly property real y: 2070.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17183;2766:9133;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24601
+ readonly property real y: 2062.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17181;2766:9059;2526:13406"
+ readonly property string filePath: "dark/images/spinbox-background.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24589
+ readonly property real y: 1988.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17181;2766:9059"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17181;2766:9059;2526:13408;4418:24767"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-background.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24681
+ readonly property real y: 1992.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17181;2766:9059;2526:13408;8858:14984"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-icon.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24692
+ readonly property real y: 2003.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17181;2766:9059;2526:13412;4418:25668"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-background.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24649
+ readonly property real y: 1992.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17181;2766:9059;2526:13412;8858:15141"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-icon.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24660
+ readonly property real y: 2003.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17181;2766:9059;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24601
+ readonly property real y: 1995.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject up_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17191;2766:9429;2526:13406"
+ readonly property string filePath: "dark/images/spinbox-background-up-hovered.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-up-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24589
+ readonly property real y: 2323.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17191;2766:9429"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-up-hovered"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17191;2766:9429;2526:13408;4418:24767"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-background-up-hovered.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-up-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24681
+ readonly property real y: 2327.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17191;2766:9429;2526:13408;8858:14984"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-icon-up-hovered.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-up-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24692
+ readonly property real y: 2338.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17191;2766:9429;2526:13412;4418:25668"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-background-up-hovered.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-up-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24649
+ readonly property real y: 2327.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17191;2766:9429;2526:13412;8858:15141"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-icon-up-hovered.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-up-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24660
+ readonly property real y: 2338.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17191;2766:9429;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-up-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24601
+ readonly property real y: 2330.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject up_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17193;2766:9503;2526:13406"
+ readonly property string filePath: "dark/images/spinbox-background-up-pressed.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-up-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24589
+ readonly property real y: 2390.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17193;2766:9503"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-up-pressed"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17193;2766:9503;2526:13408;4418:24767"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-background-up-pressed.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-up-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24681
+ readonly property real y: 2394.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17193;2766:9503;2526:13408;8858:14984"
+ readonly property string filePath: "dark/images/spinbox-indicator-down-icon-up-pressed.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-up-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24692
+ readonly property real y: 2405.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17193;2766:9503;2526:13412;4418:25668"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-background-up-pressed.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-up-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24649
+ readonly property real y: 2394.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17193;2766:9503;2526:13412;8858:15141"
+ readonly property string filePath: "dark/images/spinbox-indicator-up-icon-up-pressed.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-up-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24660
+ readonly property real y: 2405.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17193;2766:9503;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-up-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24601
+ readonly property real y: 2397.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject switch_: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17204;2531:14856;4350:34538"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2250.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17204;2531:14856"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17204;2531:14856;4350:34543"
+ readonly property string filePath: "dark/images/switch-handle-checked.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-checked"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 6
+ readonly property real topShadow: 0
+ readonly property real width: 14
+ readonly property real x: 25825.5
+ readonly property real y: 2259.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17204;2531:14856;4350:34541"
+ readonly property string filePath: "dark/images/switch-handle-background-checked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2256.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:17204;2531:14856;4350:34542"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-checked"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17204;2531:14856;6761:23654"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2256.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17212;2531:14900;4350:34538"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2454.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17212;2531:14900"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked-disabled"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17212;2531:14900;4350:34543"
+ readonly property string filePath: "dark/images/switch-handle-checked-disabled.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-checked-disabled"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 6
+ readonly property real topShadow: 0
+ readonly property real width: 14
+ readonly property real x: 25825.5
+ readonly property real y: 2463.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17212;2531:14900;4350:34541"
+ readonly property string filePath: "dark/images/switch-handle-background-checked-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked-disabled"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2460.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:17212;2531:14900;4350:34542"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-checked-disabled"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17212;2531:14900;6761:23654"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2460.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17208;8664:14952"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2352.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17208;8664:14951"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked-hovered"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17208;8664:14975"
+ readonly property string filePath: "dark/images/switch-handle-checked-hovered.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 7
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-checked-hovered"
+ readonly property real rightOffset: 6
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 7
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 25824.5
+ readonly property real y: 2360.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17208;8664:14954"
+ readonly property string filePath: "dark/images/switch-handle-background-checked-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked-hovered"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2358.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17208;8664:14955"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 2
+ readonly property string name: "switch-handle-contentItem-checked-hovered"
+ readonly property real rightPadding: 2
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17208;8664:14957"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2358.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17210;8664:14801"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2403.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17210;8664:14800"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked-pressed"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17210;8664:14824"
+ readonly property string filePath: "dark/images/switch-handle-checked-pressed.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-checked-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 7
+ readonly property real topShadow: 0
+ readonly property real width: 19
+ readonly property real x: 25821.5
+ readonly property real y: 2411.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17210;8664:14803"
+ readonly property string filePath: "dark/images/switch-handle-background-checked-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked-pressed"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2409.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:17210;8664:14804"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 2
+ readonly property string name: "switch-handle-contentItem-checked-pressed"
+ readonly property real rightPadding: 2
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17210;8664:14806"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2409.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17206;2531:14867;2942:5449"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2301.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17206;2531:14867"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-disabled"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17206;2531:14867;2531:14816"
+ readonly property string filePath: "dark/images/switch-handle-disabled.png"
+ readonly property real height: 12
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-disabled"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 6
+ readonly property real topShadow: 0
+ readonly property real width: 12
+ readonly property real x: 25806.5
+ readonly property real y: 2311.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17206;2531:14867;2531:14819"
+ readonly property string filePath: "dark/images/switch-handle-background-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-disabled"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2307.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:17206;2531:14867;2531:14811"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-handle-contentItem-disabled"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17206;2531:14867;6761:24226"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2307.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17200;8664:14878"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2148.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17200;8664:14877"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-hovered"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17200;8664:14900"
+ readonly property string filePath: "dark/images/switch-handle-hovered.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 7
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-hovered"
+ readonly property real rightOffset: 6
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 7
+ readonly property real topShadow: 0
+ readonly property real width: 14
+ readonly property real x: 25805.5
+ readonly property real y: 2157.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17200;8664:14880"
+ readonly property string filePath: "dark/images/switch-handle-background-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-hovered"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2154.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:17200;8664:14881"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-hovered"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17200;8664:14883"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2154.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17198;2531:14823;2942:5449"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2091.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17198;2531:14823"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17198;2531:14823;2531:14816"
+ readonly property string filePath: "dark/images/switch-handle.png"
+ readonly property real height: 12
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 6
+ readonly property real topShadow: 0
+ readonly property real width: 12
+ readonly property real x: 25806.5
+ readonly property real y: 2101.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17198;2531:14823;2531:14819"
+ readonly property string filePath: "dark/images/switch-handle-background.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2097.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:17198;2531:14823;2531:14811"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-handle-contentItem"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17198;2531:14823;6761:24226"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2097.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17202;8664:14715"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25798.5
+ readonly property real y: 2199.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17202;8664:14714"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-pressed"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17202;8664:14737"
+ readonly property string filePath: "dark/images/switch-handle-pressed.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 7
+ readonly property real topShadow: 0
+ readonly property real width: 17
+ readonly property real x: 25805.5
+ readonly property real y: 2208.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17202;8664:14717"
+ readonly property string filePath: "dark/images/switch-handle-background-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-pressed"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25802.5
+ readonly property real y: 2205.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:17202;8664:14718"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-pressed"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17202;8664:14720"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25854.5
+ readonly property real y: 2205.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ }
+
+ readonly property QtObject tabbar: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17270;2556:17466;2556:17413"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-background-disabled"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 470
+ readonly property real x: 26619.5
+ readonly property real y: 2847
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:17270;2556:17466"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "tabbar-contentItem-disabled"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property QtObject tabButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17270;2556:17466;2556:17415"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton1-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26623.5
+ readonly property real y: 2851
+ }
+
+ readonly property QtObject tabButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17270;2556:17466;2556:17421"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton2-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26700.5
+ readonly property real y: 2851
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject disabled_footer: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17274;2556:17577;2556:17534"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-background-disabled-footer"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 470
+ readonly property real x: 26620
+ readonly property real y: 2977
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:17274;2556:17577"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "tabbar-contentItem-disabled-footer"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property QtObject tabButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17274;2556:17577;2556:17536"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton1-disabled-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26624
+ readonly property real y: 2981
+ }
+
+ readonly property QtObject tabButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17274;2556:17577;2556:17537"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton2-disabled-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26701
+ readonly property real y: 2981
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17268;2556:17439;2556:17413"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-background"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 470
+ readonly property real x: 26620
+ readonly property real y: 2776
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:17268;2556:17439"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "tabbar-contentItem"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property QtObject tabButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17268;2556:17439;2556:17415"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton1"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26624
+ readonly property real y: 2780
+ }
+
+ readonly property QtObject tabButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17268;2556:17439;2556:17421"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton2"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26701
+ readonly property real y: 2780
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject normal_footer: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17272;2556:17555;2556:17534"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-background-normal-footer"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 470
+ readonly property real x: 26620
+ readonly property real y: 2910
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:17272;2556:17555"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "tabbar-contentItem-normal-footer"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property QtObject tabButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17272;2556:17555;2556:17536"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton1-normal-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26624
+ readonly property real y: 2914
+ }
+
+ readonly property QtObject tabButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17272;2556:17555;2556:17537"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton2-normal-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26701
+ readonly property real y: 2914
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ }
+
+ readonly property QtObject tabbutton: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17257;2556:16919;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-checked"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28285
+ readonly property real y: 1952
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:17257;2556:16919"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-checked"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17257;2556:16919;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-checked"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28297
+ readonly property real y: 1962
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17257;2556:16919;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28325
+ readonly property real y: 1962
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17263;2556:16934;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-checked-disabled"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28285
+ readonly property real y: 2153
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:17263;2556:16934"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-checked-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17263;2556:16934;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28297
+ readonly property real y: 2163
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17263;2556:16934;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28325
+ readonly property real y: 2163
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17261;2556:16929;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-checked-hovered"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28285
+ readonly property real y: 2086
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:17261;2556:16929"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-checked-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17261;2556:16929;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28297
+ readonly property real y: 2096
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17261;2556:16929;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28325
+ readonly property real y: 2096
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17265;2556:16939;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-checked-pressed"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28285
+ readonly property real y: 2220
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:17265;2556:16939"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-checked-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17265;2556:16939;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28297
+ readonly property real y: 2230
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17265;2556:16939;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28325
+ readonly property real y: 2230
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17259;2556:16924;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-disabled"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28285
+ readonly property real y: 2023.24
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:17259;2556:16924"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17259;2556:16924;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28297
+ readonly property real y: 2033.24
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17259;2556:16924;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28325
+ readonly property real y: 2033.24
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17253;2556:16909;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-hovered"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28285
+ readonly property real y: 1818
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:17253;2556:16909"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17253;2556:16909;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28297
+ readonly property real y: 1828
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17253;2556:16909;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28325
+ readonly property real y: 1828
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17251;2556:16904;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28285
+ readonly property real y: 1751
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:17251;2556:16904"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17251;2556:16904;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28297
+ readonly property real y: 1761
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17251;2556:16904;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28325
+ readonly property real y: 1761
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17255;2556:16914;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-pressed"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28285
+ readonly property real y: 1885
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:17255;2556:16914"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17255;2556:16914;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28297
+ readonly property real y: 1895
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17255;2556:16914;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28325
+ readonly property real y: 1895
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ }
+
+ readonly property QtObject textarea: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17226;2554:13608;2554:13585"
+ readonly property string filePath: "dark/images/textarea-background-disabled.png"
+ readonly property real height: 52
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 202
+ readonly property real x: 30416.5
+ readonly property real y: 2589
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17226;2554:13608"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textarea-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17226;2554:13608;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30428.5
+ readonly property real y: 2595
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject focused: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2654:6248;2654:5963;2554:13585"
+ readonly property string filePath: "dark/images/textarea-background-focused.png"
+ readonly property real height: 52
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-background-focused"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 202
+ readonly property real x: 30416.5
+ readonly property real y: 2666
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2654:6248;2654:5963"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textarea-contentItem-focused"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2654:6248;2654:5963;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label-focused"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30428.5
+ readonly property real y: 2672
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17224;2554:13603;2554:13585"
+ readonly property string filePath: "dark/images/textarea-background-hovered.png"
+ readonly property real height: 52
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 202
+ readonly property real x: 30416.5
+ readonly property real y: 2512
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17224;2554:13603"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textarea-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17224;2554:13603;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30428.5
+ readonly property real y: 2518
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17222;2554:13588;2554:13585"
+ readonly property string filePath: "dark/images/textarea-background.png"
+ readonly property real height: 52
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 202
+ readonly property real x: 30416.5
+ readonly property real y: 2435
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:17222;2554:13588"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textarea-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17222;2554:13588;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30428.5
+ readonly property real y: 2441
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 6
+ }
+
+ }
+
+ readonly property QtObject textfield: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17219;2537:15922;2537:15894"
+ readonly property string filePath: "dark/images/textfield-background-disabled.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 160
+ readonly property real x: 29551
+ readonly property real y: 1873.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17219;2537:15922"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17219;2537:15922;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29563
+ readonly property real y: 1878.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject focused: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2644:5979;2644:5955;2537:15894"
+ readonly property string filePath: "dark/images/textfield-background-focused.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-background-focused"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 160
+ readonly property real x: 29551
+ readonly property real y: 1942.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2644:5979;2644:5955"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem-focused"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2644:5979;2644:5955;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label-focused"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29563
+ readonly property real y: 1947.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17217;2537:15917;2537:15894"
+ readonly property string filePath: "dark/images/textfield-background-hovered.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 160
+ readonly property real x: 29551
+ readonly property real y: 1804.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17217;2537:15917"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17217;2537:15917;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29563
+ readonly property real y: 1809.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17215;2537:15912;2537:15894"
+ readonly property string filePath: "dark/images/textfield-background.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 160
+ readonly property real x: 29551
+ readonly property real y: 1735.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:17215;2537:15912"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17215;2537:15912;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29563
+ readonly property real y: 1740.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject toolbar: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5826;2556:19625;2556:19554"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-background-disabled"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 225
+ readonly property real x: 31702
+ readonly property real y: 2862
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2942:5826;2556:19625"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "toolbar-contentItem-disabled"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property QtObject toolButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5826;2556:19625;2556:19556"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton1-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31706
+ readonly property real y: 2869
+ }
+
+ readonly property QtObject toolButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5826;2556:19625;2556:19562"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton2-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31779
+ readonly property real y: 2869
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject disabled_footer: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5830;2556:19669;2556:19582"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-background-disabled-footer"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 225
+ readonly property real x: 31702
+ readonly property real y: 2996
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2942:5830;2556:19669"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "toolbar-contentItem-disabled-footer"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property QtObject toolButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5830;2556:19669;2556:19584"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton1-disabled-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31706
+ readonly property real y: 3003
+ }
+
+ readonly property QtObject toolButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5830;2556:19669;2556:19585"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton2-disabled-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31779
+ readonly property real y: 3003
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5824;2556:19603;2556:19554"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-background"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 225
+ readonly property real x: 31702
+ readonly property real y: 2795
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2942:5824;2556:19603"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "toolbar-contentItem"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property QtObject toolButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5824;2556:19603;2556:19556"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton1"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31706
+ readonly property real y: 2802
+ }
+
+ readonly property QtObject toolButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5824;2556:19603;2556:19562"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton2"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31779
+ readonly property real y: 2802
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject normal_footer: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5828;2556:19647;2556:19582"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-background-normal-footer"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 225
+ readonly property real x: 31702
+ readonly property real y: 2929
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2942:5828;2556:19647"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "toolbar-contentItem-normal-footer"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property QtObject toolButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5828;2556:19647;2556:19584"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton1-normal-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31706
+ readonly property real y: 2936
+ }
+
+ readonly property QtObject toolButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5828;2556:19647;2556:19585"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton2-normal-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31779
+ readonly property real y: 2936
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ }
+
+ readonly property QtObject toolbutton: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17283;2556:18709;2556:18691"
+ readonly property string filePath: "dark/images/toolbutton-background-checked.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33221
+ readonly property real y: 1942
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:17283;2556:18709"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-checked"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17283;2556:18709;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-checked"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33232
+ readonly property real y: 1951
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17283;2556:18709;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33256
+ readonly property real y: 1949
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17289;2556:18724;2556:18691"
+ readonly property string filePath: "dark/images/toolbutton-background-checked-disabled.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33221
+ readonly property real y: 2143
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:17289;2556:18724"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-checked-disabled"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17289;2556:18724;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33232
+ readonly property real y: 2152
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17289;2556:18724;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33256
+ readonly property real y: 2150
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17287;2556:18719;2556:18691"
+ readonly property string filePath: "dark/images/toolbutton-background-checked-hovered.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33221
+ readonly property real y: 2077
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:17287;2556:18719"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-checked-hovered"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17287;2556:18719;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33232
+ readonly property real y: 2086
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17287;2556:18719;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33256
+ readonly property real y: 2084
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17291;2556:18729;2556:18691"
+ readonly property string filePath: "dark/images/toolbutton-background-checked-pressed.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33221
+ readonly property real y: 2212
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:17291;2556:18729"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-checked-pressed"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17291;2556:18729;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33232
+ readonly property real y: 2221
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17291;2556:18729;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33256
+ readonly property real y: 2219
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17285;2556:18714;2556:18691"
+ readonly property string filePath: "dark/images/toolbutton-background-disabled.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33221
+ readonly property real y: 2009
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:17285;2556:18714"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-disabled"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17285;2556:18714;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33232
+ readonly property real y: 2018
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17285;2556:18714;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33256
+ readonly property real y: 2016
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17279;2556:18699;2556:18691"
+ readonly property string filePath: "dark/images/toolbutton-background-hovered.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33221
+ readonly property real y: 1808
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:17279;2556:18699"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-hovered"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17279;2556:18699;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33232
+ readonly property real y: 1817
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17279;2556:18699;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33256
+ readonly property real y: 1815
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17277;2556:18694;2556:18691"
+ readonly property string filePath: ""
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33221
+ readonly property real y: 1741
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:17277;2556:18694"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17277;2556:18694;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33232
+ readonly property real y: 1750
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17277;2556:18694;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33256
+ readonly property real y: 1748
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:17281;2556:18704;2556:18691"
+ readonly property string filePath: "dark/images/toolbutton-background-pressed.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33221
+ readonly property real y: 1866
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:17281;2556:18704"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-pressed"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17281;2556:18704;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33232
+ readonly property real y: 1875
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:17281;2556:18704;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33256
+ readonly property real y: 1873
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ }
+
+ }
+ }
+ readonly property QtObject light: QtObject {
+ readonly property QtObject controls: QtObject {
+ readonly property QtObject button: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15399;2356:10516;2373:10903"
+ readonly property string filePath: "light/images/button-background-checked.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2467
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15399;2356:10516"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15399;2356:10516;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2475
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15399;2356:10516;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2473
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15405;2356:10522;2373:10903"
+ readonly property string filePath: "light/images/button-background-checked-disabled.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2668
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15405;2356:10522"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15405;2356:10522;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2676
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15405;2356:10522;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2674
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15403;2356:10520;2373:10903"
+ readonly property string filePath: "light/images/button-background-checked-hovered.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2601
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15403;2356:10520"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15403;2356:10520;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2609
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15403;2356:10520;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2607
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15407;2356:10524;2373:10903"
+ readonly property string filePath: "light/images/button-background-checked-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2735
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15407;2356:10524"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-checked-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15407;2356:10524;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2743
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15407;2356:10524;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2741
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15401;2356:10518;2373:10903"
+ readonly property string filePath: "light/images/button-background-disabled.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2534
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15401;2356:10518"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15401;2356:10518;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2542
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15401;2356:10518;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2540
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15395;2356:10512;2373:10903"
+ readonly property string filePath: "light/images/button-background-hovered.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2333
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15395;2356:10512"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15395;2356:10512;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2341
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15395;2356:10512;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2339
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15393;2356:10510;2373:10903"
+ readonly property string filePath: "light/images/button-background.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2227.5
+ readonly property real y: 2277
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15393;2356:10510"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15393;2356:10510;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2247.5
+ readonly property real y: 2285
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15393;2356:10510;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2271.5
+ readonly property real y: 2283
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15397;2356:10514;2373:10903"
+ readonly property string filePath: "light/images/button-background-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "button-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 98
+ readonly property real x: 2225
+ readonly property real y: 2400
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15397;2356:10514"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "button-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15397;2356:10514;4693:13271"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "button-icon-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 2245
+ readonly property real y: 2408
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15397;2356:10514;2248:10452"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "button-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 2269
+ readonly property real y: 2406
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject checkbox: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15416;2829:5675;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 1941.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:15416;2829:5675"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15416;2829:5675;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-checked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 1946.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15416;2829:5675;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 1946.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15426;2427:12224;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2217.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:15426;2427:12224"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15426;2427:12224;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-checked-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2222.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15426;2427:12224;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2222.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15430;2829:5737;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2079.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:15430;2829:5737"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15430;2829:5737;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-checked-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2084.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15430;2829:5737;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2084.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15428;2425:12191;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2148.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:15428;2425:12191"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-checked-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15428;2425:12191;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-checked-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-checked-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2153.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15428;2425:12191;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2153.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15432;2829:5710;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2010.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:15432;2829:5710"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15432;2829:5710;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2015.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15432;2829:5710;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2015.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled_partiallyChecked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15424;2427:12263;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-disabled-partiallyChecked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2493.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:15424;2427:12263"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-disabled-partiallyChecked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15424;2427:12263;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-disabled-partiallyChecked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-disabled-partiallyChecked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2498.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15424;2427:12263;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-disabled-partiallyChecked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2498.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15412;2829:5612;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 1803.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:15412;2829:5612"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15412;2829:5612;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 1808.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15412;2829:5612;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 1808.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered_partiallyChecked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15420;2427:12244;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-hovered-partiallyChecked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2355.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:15420;2427:12244"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-hovered-partiallyChecked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15420;2427:12244;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-hovered-partiallyChecked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-hovered-partiallyChecked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2360.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15420;2427:12244;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-hovered-partiallyChecked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2360.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15410;2829:5455;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 1734.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:15410;2829:5455"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15410;2829:5455;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 1739.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15410;2829:5455;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 1739.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject partiallyChecked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15418;2427:12233;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-partiallyChecked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2286.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:15418;2427:12233"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-partiallyChecked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15418;2427:12233;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-partiallyChecked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-partiallyChecked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2291.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15418;2427:12233;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-partiallyChecked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2291.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject partiallyChecked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15422;2427:12254;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-partiallyChecked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 2424.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:15422;2427:12254"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-partiallyChecked-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15422;2427:12254;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-partiallyChecked-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-partiallyChecked-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 2429.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15422;2427:12254;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-partiallyChecked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 2429.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15414;2829:5648;2425:10961"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 73
+ readonly property real x: 4752.5
+ readonly property real y: 1872.5
+ }
+
+ readonly property real bottomPadding: 7
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 7
+ readonly property string figmaId: "I2557:15414;2829:5648"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "checkbox-contentItem-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15414;2829:5648;2425:10953"
+ readonly property string filePath: "light/images/checkbox-indicator-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-indicator-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 4756.5
+ readonly property real y: 1877.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15414;2829:5648;6820:12339"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "checkbox-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 4784.5
+ readonly property real y: 1877.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject combobox: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15447;2407:10440;2397:10728"
+ readonly property string filePath: "light/images/combobox-background-disabled.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7575
+ readonly property real y: 4817
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15447;2407:10440"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15447;2407:10440;2397:10731"
+ readonly property string filePath: "light/images/combobox-indicator-disabled.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 7672
+ readonly property real y: 4825
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15447;2407:10440;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 7588
+ readonly property real y: 4823
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:15447;2407:10440;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-disabled"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:15447;2407:10440;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-disabled"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15447;2407:10440;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-disabled"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7575
+ readonly property real y: 4849
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15447;2407:10440;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-disabled"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject focused: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4677:11371;4606:28948;2397:10728"
+ readonly property string filePath: "light/images/combobox-background-focused.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-focused"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7575
+ readonly property real y: 4884
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4677:11371;4606:28948"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-focused"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4677:11371;4606:28948;2397:10731"
+ readonly property string filePath: "light/images/combobox-indicator-focused.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-focused"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 7672
+ readonly property real y: 4892
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4677:11371;4606:28948;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-focused"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 7588
+ readonly property real y: 4890
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4677:11371;4606:28948;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-focused"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4677:11371;4606:28948;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-focused"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4677:11371;4606:28948;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-focused"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7575
+ readonly property real y: 4916
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4677:11371;4606:28948;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-focused"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15437;2397:10784;2397:10728"
+ readonly property string filePath: "light/images/combobox-background-hovered.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7551.5
+ readonly property real y: 3996
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15437;2397:10784"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15437;2397:10784;2397:10731"
+ readonly property string filePath: "light/images/combobox-indicator-hovered.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 7648.5
+ readonly property real y: 4004
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15437;2397:10784;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 7564.5
+ readonly property real y: 4002
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:15437;2397:10784;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-hovered"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:15437;2397:10784;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-hovered"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15437;2397:10784;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-hovered"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7551.5
+ readonly property real y: 4028
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15437;2397:10784;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-hovered"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered_open: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15443;2407:10424;2397:10728"
+ readonly property string filePath: "light/images/combobox-background-hovered-open.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-hovered-open"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7575
+ readonly property real y: 4359
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15443;2407:10424"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-hovered-open"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15443;2407:10424;2397:10731"
+ readonly property string filePath: "light/images/combobox-indicator-hovered-open.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-hovered-open"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 7672
+ readonly property real y: 4367
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15443;2407:10424;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-hovered-open"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 7588
+ readonly property real y: 4365
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:15443;2407:10424;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-hovered-open"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:15443;2407:10424;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-hovered-open"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15443;2407:10424;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-hovered-open"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7575
+ readonly property real y: 4391
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15443;2407:10424;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-hovered-open"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15435;2397:10736;2397:10728"
+ readonly property string filePath: "light/images/combobox-background.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7551.5
+ readonly property real y: 3929
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15435;2397:10736"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15435;2397:10736;2397:10731"
+ readonly property string filePath: "light/images/combobox-indicator.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 7648.5
+ readonly property real y: 3937
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15435;2397:10736;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 7564.5
+ readonly property real y: 3935
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:15435;2397:10736;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:15435;2397:10736;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15435;2397:10736;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7551.5
+ readonly property real y: 3961
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15435;2397:10736;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject open: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15441;2399:10706;2397:10728"
+ readonly property string filePath: "light/images/combobox-background-open.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-open"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7575
+ readonly property real y: 4130
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15441;2399:10706"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-open"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15441;2399:10706;2397:10731"
+ readonly property string filePath: "light/images/combobox-indicator-open.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-open"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 7672
+ readonly property real y: 4138
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15441;2399:10706;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-open"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 7588
+ readonly property real y: 4136
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:15441;2399:10706;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-open"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:15441;2399:10706;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-open"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15441;2399:10706;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-open"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7575
+ readonly property real y: 4162
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15441;2399:10706;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-open"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject open_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15445;2407:10432;2397:10728"
+ readonly property string filePath: "light/images/combobox-background-open-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-open-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7575
+ readonly property real y: 4585
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15445;2407:10432"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-open-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15445;2407:10432;2397:10731"
+ readonly property string filePath: "light/images/combobox-indicator-open-pressed.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-open-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 7672
+ readonly property real y: 4593
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15445;2407:10432;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-open-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 7588
+ readonly property real y: 4591
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:15445;2407:10432;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-open-pressed"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:15445;2407:10432;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-open-pressed"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15445;2407:10432;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-open-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7575
+ readonly property real y: 4617
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15445;2407:10432;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-open-pressed"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15439;2397:10792;2397:10728"
+ readonly property string filePath: "light/images/combobox-background-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7575
+ readonly property real y: 4063
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15439;2397:10792"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "combobox-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15439;2397:10792;2397:10731"
+ readonly property string filePath: "light/images/combobox-indicator-pressed.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-indicator-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 7672
+ readonly property real y: 4071
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15439;2397:10792;4606:26776;4606:10833"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 7588
+ readonly property real y: 4069
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:15439;2397:10792;4606:26776;4606:10833"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "combobox-label-contentItem-pressed"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:15439;2397:10792;4606:26776;4606:10837"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "combobox-label-text-pressed"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15439;2397:10792;2422:10283;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "combobox-popup-background-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 7575
+ readonly property real y: 4095
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15439;2397:10792;2422:10283;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "combobox-popup-contentItem-pressed"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 51
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject editablecombobox: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9446;4610:29709;4610:29350"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-disabled"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8638
+ readonly property real y: 4817.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9446;4610:29709"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9446;4610:29709;4610:29356"
+ readonly property string filePath: ""
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8734
+ readonly property real y: 4825
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9446;4610:29709;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8652
+ readonly property real y: 4822
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9446;4610:29709;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-disabled"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9446;4610:29709;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-disabled"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9446;4610:29709;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-popup-background-disabled"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8639
+ readonly property real y: 4848.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9446;4610:29709;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-disabled"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject focused: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4677:11569;4610:29759;4610:29350"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-focused"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8638
+ readonly property real y: 4884.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4677:11569;4610:29759"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-focused"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4677:11569;4610:29759;4610:29356"
+ readonly property string filePath: ""
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-focused"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8734
+ readonly property real y: 4892
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4677:11569;4610:29759;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-focused"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8652
+ readonly property real y: 4889
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4677:11569;4610:29759;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-focused"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4677:11569;4610:29759;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-focused"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4677:11569;4610:29759;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-popup-background-focused"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8639
+ readonly property real y: 4915.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4677:11569;4610:29759;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-focused"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9436;4610:29459;4610:29350"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-hovered"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8638
+ readonly property real y: 3996.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9436;4610:29459"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9436;4610:29459;4610:29356"
+ readonly property string filePath: ""
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8734
+ readonly property real y: 4004
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9436;4610:29459;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8652
+ readonly property real y: 4001
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9436;4610:29459;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-hovered"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9436;4610:29459;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-hovered"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9436;4610:29459;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-popup-background-hovered"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8639
+ readonly property real y: 4027.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9436;4610:29459;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-hovered"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered_open: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9442;4610:29609;4610:29350"
+ readonly property string filePath: "light/images/editablecombobox-background-hovered-open.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-hovered-open"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8638
+ readonly property real y: 4359.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9442;4610:29609"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-hovered-open"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9442;4610:29609;4610:29356"
+ readonly property string filePath: "light/images/editablecombobox-indicator-hovered-open.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-hovered-open"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8734
+ readonly property real y: 4367
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9442;4610:29609;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-hovered-open"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8652
+ readonly property real y: 4364
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9442;4610:29609;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-hovered-open"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9442;4610:29609;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-hovered-open"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 8
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9442;4610:29609;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: "light/images/editablecombobox-popup-background-hovered-open.png"
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 4
+ readonly property string name: "editablecombobox-popup-background-hovered-open"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 4
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8639
+ readonly property real y: 4390.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9442;4610:29609;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-hovered-open"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9434;4610:29409;4610:29350"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8638
+ readonly property real y: 3929.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9434;4610:29409"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9434;4610:29409;4610:29356"
+ readonly property string filePath: ""
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8734
+ readonly property real y: 3937
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9434;4610:29409;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8652
+ readonly property real y: 3934
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9434;4610:29409;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9434;4610:29409;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9434;4610:29409;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-popup-background"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8639
+ readonly property real y: 3960.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9434;4610:29409;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject open: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9440;4610:29559;4610:29350"
+ readonly property string filePath: "light/images/editablecombobox-background-open.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-open"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8638
+ readonly property real y: 4130.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9440;4610:29559"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-open"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9440;4610:29559;4610:29356"
+ readonly property string filePath: "light/images/editablecombobox-indicator-open.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-open"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8734
+ readonly property real y: 4138
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9440;4610:29559;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-open"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8652
+ readonly property real y: 4135
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9440;4610:29559;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-open"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9440;4610:29559;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-open"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 8
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9440;4610:29559;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: "light/images/editablecombobox-popup-background-open.png"
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 4
+ readonly property string name: "editablecombobox-popup-background-open"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 4
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8639
+ readonly property real y: 4161.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9440;4610:29559;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-open"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject open_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9444;4610:29659;4610:29350"
+ readonly property string filePath: "light/images/editablecombobox-background-open-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-open-pressed"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8638
+ readonly property real y: 4585.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9444;4610:29659"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-open-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9444;4610:29659;4610:29356"
+ readonly property string filePath: "light/images/editablecombobox-indicator-open-pressed.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-open-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8734
+ readonly property real y: 4593
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9444;4610:29659;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-open-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8652
+ readonly property real y: 4590
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9444;4610:29659;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-open-pressed"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9444;4610:29659;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-open-pressed"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 8
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9444;4610:29659;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: "light/images/editablecombobox-popup-background-open-pressed.png"
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 4
+ readonly property string name: "editablecombobox-popup-background-open-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 4
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8639
+ readonly property real y: 4616.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9444;4610:29659;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-open-pressed"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9438;4610:29509;4610:29350"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 5
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-background-pressed"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 5
+ readonly property real topShadow: 0
+ readonly property real width: 128
+ readonly property real x: 8638
+ readonly property real y: 4063.17
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9438;4610:29509"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "editablecombobox-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9438;4610:29509;4610:29356"
+ readonly property string filePath: ""
+ readonly property real height: 16
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-indicator-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 8734
+ readonly property real y: 4071
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9438;4610:29509;4435:10776;4435:10687"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 8652
+ readonly property real y: 4068
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9438;4610:29509;4435:10776;4435:10687"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "editablecombobox-label-contentItem-pressed"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I4435:9438;4610:29509;4435:10776;4435:10690"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "editablecombobox-label-text-pressed"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property QtObject popup_background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9438;4610:29509;4435:10720;3079:5526;2308:11133;2313:11247"
+ readonly property string filePath: ""
+ readonly property real height: 118
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "editablecombobox-popup-background-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 126
+ readonly property real x: 8639
+ readonly property real y: 4094.24
+ }
+
+ readonly property QtObject popup_contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I4435:9438;4610:29509;4435:10720;3079:5526;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 1
+ readonly property string name: "editablecombobox-popup-contentItem-pressed"
+ readonly property real rightPadding: 1
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property real rightPadding: 12
+ readonly property real spacing: 57
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject flatbutton: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9165;3987:9104;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-checked.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 2039.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9165;3987:9104"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9165;3987:9104;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 2045.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9165;3987:9104;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 2045.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9168;3987:9122;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-checked-disabled.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked-disabled"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 2173.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9168;3987:9122"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9168;3987:9122;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 2179.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9168;3987:9122;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 2179.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9167;3987:9113;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-checked-hovered.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked-hovered"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 2106.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9167;3987:9113"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9167;3987:9113;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 2112.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9167;3987:9113;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 2112.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9169;3987:9131;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-checked-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-checked-pressed"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 2240.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9169;3987:9131"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-checked-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9169;3987:9131;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 2246.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9169;3987:9131;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 2246.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9166;3987:9095;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-disabled.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-disabled"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 1972.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9166;3987:9095"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9166;3987:9095;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 1978.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9166;3987:9095;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 1978.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9163;3987:9077;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-hovered.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-hovered"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 1838.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9163;3987:9077"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9163;3987:9077;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 1844.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9163;3987:9077;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 1844.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9162;3987:9068;3987:9044"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 1771.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9162;3987:9068"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9162;3987:9068;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 1777.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9162;3987:9068;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 1777.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I3991:9164;3987:9086;3987:9044"
+ readonly property string filePath: "light/images/flatbutton-background-pressed.png"
+ readonly property real height: 32
+ readonly property real leftOffset: 12
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-background-pressed"
+ readonly property real rightOffset: 12
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 16
+ readonly property real topShadow: 0
+ readonly property real width: 96
+ readonly property real x: 3172.5
+ readonly property real y: 1905.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I3991:9164;3987:9086"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "flatbutton-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9164;3987:9086;4709:15937"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-icon-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 3189.5
+ readonly property real y: 1911.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I3991:9164;3987:9086;3987:9039"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "flatbutton-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 34
+ readonly property real x: 3217.5
+ readonly property real y: 1911.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject frame: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15481;2439:15806;2439:15811"
+ readonly property string filePath: "light/images/frame-background-disabled.png"
+ readonly property real height: 52
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "frame-background-disabled"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 65
+ readonly property real x: 11481.5
+ readonly property real y: 3009
+ }
+
+ readonly property real bottomPadding: 16
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 16
+ readonly property string figmaId: "I2557:15481;2439:15806"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 16
+ readonly property string name: "frame-contentItem-disabled"
+ readonly property real rightPadding: 16
+ readonly property real spacing: 0
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15481;2439:15806;2439:15788"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "frame-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 11497.5
+ readonly property real y: 3025
+ }
+
+ readonly property real leftPadding: 16
+ readonly property real rightPadding: 16
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15479;2439:15801;2439:15811"
+ readonly property string filePath: "light/images/frame-background.png"
+ readonly property real height: 52
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "frame-background"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 65
+ readonly property real x: 11481.5
+ readonly property real y: 2797
+ }
+
+ readonly property real bottomPadding: 16
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 16
+ readonly property string figmaId: "I2557:15479;2439:15801"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 16
+ readonly property string name: "frame-contentItem"
+ readonly property real rightPadding: 16
+ readonly property real spacing: 0
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15479;2439:15801;2439:15788"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "frame-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 11497.5
+ readonly property real y: 2813
+ }
+
+ readonly property real leftPadding: 16
+ readonly property real rightPadding: 16
+ readonly property real topPadding: 16
+ }
+
+ }
+
+ readonly property QtObject groupbox: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15609;2556:14470;2554:14173"
+ readonly property string filePath: ""
+ readonly property real height: 52
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-background-disabled"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 12727.5
+ readonly property real y: 3721
+ }
+
+ readonly property real bottomPadding: 16
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 16
+ readonly property string figmaId: "I2557:15609;2556:14470;4176:22635"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 16
+ readonly property string name: "groupbox-contentItem-disabled"
+ readonly property real rightPadding: 16
+ readonly property real spacing: 0
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15609;2556:14470;4330:10056"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 12727.5
+ readonly property real y: 3693
+ }
+
+ readonly property QtObject label_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15609;2556:14470;4330:10056;4330:10044"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-label-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 12727.5
+ readonly property real y: 3693
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:15609;2556:14470;4330:10056"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "groupbox-label-contentItem-disabled"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:15609;2556:14470;4330:10056;4330:9505"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "groupbox-label-text-disabled"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 16
+ readonly property real rightPadding: 16
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15607;2556:14430;2554:14173"
+ readonly property string filePath: ""
+ readonly property real height: 52
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-background-hovered"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 12727.5
+ readonly property real y: 3508
+ }
+
+ readonly property real bottomPadding: 16
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 16
+ readonly property string figmaId: "I2557:15607;2556:14430;4176:22635"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 16
+ readonly property string name: "groupbox-contentItem-hovered"
+ readonly property real rightPadding: 16
+ readonly property real spacing: 0
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15607;2556:14430;4330:10056"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 12727.5
+ readonly property real y: 3480
+ }
+
+ readonly property QtObject label_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15607;2556:14430;4330:10056;4330:10044"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-label-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 12727.5
+ readonly property real y: 3480
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:15607;2556:14430;4330:10056"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "groupbox-label-contentItem-hovered"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:15607;2556:14430;4330:10056;4330:9505"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "groupbox-label-text-hovered"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 16
+ readonly property real rightPadding: 16
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15605;2556:14390;2554:14173"
+ readonly property string filePath: ""
+ readonly property real height: 52
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-background"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 12727
+ readonly property real y: 3296
+ }
+
+ readonly property real bottomPadding: 16
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 16
+ readonly property string figmaId: "I2557:15605;2556:14390;4176:22635"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 16
+ readonly property string name: "groupbox-contentItem"
+ readonly property real rightPadding: 16
+ readonly property real spacing: 0
+ readonly property real topPadding: 16
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15605;2556:14390;4330:10056"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-label"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 12727
+ readonly property real y: 3268
+ }
+
+ readonly property QtObject label_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15605;2556:14390;4330:10056;4330:10044"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "groupbox-label-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 72
+ readonly property real x: 12727
+ readonly property real y: 3268
+ }
+
+ readonly property QtObject label_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I2557:15605;2556:14390;4330:10056"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "groupbox-label-contentItem"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject label_text: QtObject {
+ readonly property string figmaId: "I2557:15605;2556:14390;4330:10056;4330:9505"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property string name: "groupbox-label-text"
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ }
+
+ readonly property real leftPadding: 16
+ readonly property real rightPadding: 16
+ readonly property real topPadding: 16
+ }
+
+ }
+
+ readonly property QtObject itemdelegate: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15461;2319:9946;2399:11597"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5697
+ readonly property real y: 2010.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:15461;2319:9946"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15461;2319:9946;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5704.5
+ readonly property real y: 2018.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject highlighted: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15463;2319:9952;2399:11597"
+ readonly property string filePath: "light/images/itemdelegate-background-highlighted.png"
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background-highlighted"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5697
+ readonly property real y: 2077.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:15463;2319:9952"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem-highlighted"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15463;2319:9952;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label-highlighted"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5704.5
+ readonly property real y: 2085.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject highlighted_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15465;2319:9958;2399:11597"
+ readonly property string filePath: "light/images/itemdelegate-background-highlighted-hovered.png"
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background-highlighted-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5697
+ readonly property real y: 2137.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:15465;2319:9958"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem-highlighted-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15465;2319:9958;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label-highlighted-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5704.5
+ readonly property real y: 2145.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject highlighted_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15467;2319:9970;2399:11597"
+ readonly property string filePath: "light/images/itemdelegate-background-highlighted-pressed.png"
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background-highlighted-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5697
+ readonly property real y: 2211.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:15467;2319:9970"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem-highlighted-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15467;2319:9970;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label-highlighted-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5704.5
+ readonly property real y: 2219.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15457;2319:9922;2399:11597"
+ readonly property string filePath: "light/images/itemdelegate-background-hovered.png"
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5697
+ readonly property real y: 1876.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:15457;2319:9922"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15457;2319:9922;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5704.5
+ readonly property real y: 1884.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15455;2319:9916;2399:11597"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5697
+ readonly property real y: 1810.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:15455;2319:9916"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15455;2319:9916;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5704.5
+ readonly property real y: 1818.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15459;2319:9934;2399:11597"
+ readonly property string filePath: "light/images/itemdelegate-background-pressed.png"
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 93
+ readonly property real x: 5697
+ readonly property real y: 1943.5
+ }
+
+ readonly property real bottomPadding: 8
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 8
+ readonly property string figmaId: "I2557:15459;2319:9934"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "itemdelegate-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 12
+ readonly property real topPadding: 8
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15459;2319:9934;2411:10964"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "itemdelegate-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 5704.5
+ readonly property real y: 1951.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 8
+ }
+
+ }
+
+ readonly property QtObject popup: QtObject {
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 8
+ readonly property real bottomShadow: 8
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15450;2308:11133;2313:11247"
+ readonly property string filePath: "light/images/popup-background.png"
+ readonly property real height: 106
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 4
+ readonly property string name: "popup-background"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 4
+ readonly property real topOffset: 8
+ readonly property real topShadow: 0
+ readonly property real width: 118
+ readonly property real x: 6927
+ readonly property real y: 2194
+ }
+
+ readonly property real bottomPadding: 16
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 16
+ readonly property string figmaId: "I2557:15450;2308:11133"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 16
+ readonly property string name: "popup-contentItem"
+ readonly property real rightPadding: 16
+ readonly property real spacing: 0
+ readonly property real topPadding: 16
+ }
+
+ readonly property real leftPadding: 16
+ readonly property real rightPadding: 16
+ readonly property real topPadding: 16
+ }
+
+ }
+
+ readonly property QtObject progressbar: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9316;4304:9328"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem-disabled"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9316;4304:9328;4413:23724"
+ readonly property string filePath: "light/images/progressbar-groove-disabled.png"
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15598
+ readonly property real y: 2059
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9316;4304:9328;4267:14564"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15598
+ readonly property real y: 2058
+ }
+
+ }
+
+ readonly property QtObject disabled_indeterminate: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9318;4304:9355"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem-disabled-indeterminate"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9318;4304:9355;4350:35746"
+ readonly property string filePath: ""
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove-disabled-indeterminate"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15598
+ readonly property real y: 2132
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9318;4304:9355;4403:22724"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track-disabled-indeterminate"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15664
+ readonly property real y: 2131
+ }
+
+ }
+
+ readonly property QtObject indeterminate: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9317;2450:12847"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem-indeterminate"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9317;2450:12847;4350:35746"
+ readonly property string filePath: ""
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove-indeterminate"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15598
+ readonly property real y: 1986
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9317;2450:12847;4403:22724"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track-indeterminate"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15664
+ readonly property real y: 1985
+ }
+
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property real bottomPadding: 0
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 0
+ readonly property string figmaId: "I4435:9315;2450:12841"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 0
+ readonly property string name: "progressbar-contentItem"
+ readonly property real rightPadding: 0
+ readonly property real spacing: 0
+ readonly property real topPadding: 0
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I4435:9315;2450:12841;4413:23724"
+ readonly property string filePath: "light/images/progressbar-groove.png"
+ readonly property real height: 1
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-groove"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 180
+ readonly property real x: 15598
+ readonly property real y: 1913
+ }
+
+ readonly property real leftPadding: 0
+ readonly property real rightPadding: 0
+ readonly property real topPadding: 0
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I4435:9315;2450:12841;4267:14564"
+ readonly property real height: 3
+ readonly property real leftShadow: 0
+ readonly property string name: "progressbar-track"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 48
+ readonly property real x: 15598
+ readonly property real y: 1912
+ }
+
+ }
+
+ }
+
+ readonly property QtObject radiobutton: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15511;2483:15472;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 1977.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15511;2483:15472"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15511;2483:15472;2473:12871"
+ readonly property string filePath: "light/images/radiobutton-indicator-checked.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 1983.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15511;2483:15472;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 1985.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15517;2488:15512;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 2255.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15517;2488:15512"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15517;2488:15512;2473:12871"
+ readonly property string filePath: "light/images/radiobutton-indicator-checked-disabled.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 2261.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15517;2488:15512;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 2263.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15513;8622:14986"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 2119.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15513;8622:14985"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15513;8622:14996"
+ readonly property string filePath: "light/images/radiobutton-indicator-checked-hovered.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 2125.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15513;8622:14988"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 2127.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15515;8622:15023"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 2186.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15515;8622:15022"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-checked-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15515;8622:15033"
+ readonly property string filePath: "light/images/radiobutton-indicator-checked-pressed.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-checked-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 2192.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15515;8622:15025"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 2194.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15519;2483:15480;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 2048.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15519;2483:15480"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15519;2483:15480;2473:12871"
+ readonly property string filePath: "light/images/radiobutton-indicator-disabled.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 2054.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15519;2483:15480;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 2056.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15507;2473:12899;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 1839.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15507;2473:12899"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15507;2473:12899;2473:12871"
+ readonly property string filePath: "light/images/radiobutton-indicator-hovered.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 1845.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15507;2473:12899;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 1847.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15505;2473:12891;2472:12869"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 1770.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15505;2473:12891"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15505;2473:12891;2473:12871"
+ readonly property string filePath: "light/images/radiobutton-indicator.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 1776.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15505;2473:12891;6758:14518"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 1778.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15509;8622:15060"
+ readonly property string filePath: ""
+ readonly property real height: 36
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 16867.5
+ readonly property real y: 1908.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15509;8622:15059"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "radiobutton-contentItem-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject indicator: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15509;8622:15070"
+ readonly property string filePath: "light/images/radiobutton-indicator-pressed.png"
+ readonly property real height: 24
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-indicator-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 24
+ readonly property real x: 16871.5
+ readonly property real y: 1914.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15509;8622:15062"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "radiobutton-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 16903.5
+ readonly property real y: 1916.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: 8
+ readonly property real topPadding: 6
+ }
+
+ }
+
+ readonly property QtObject rangeslider: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15528;2509:12481;2509:12419"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17634
+ readonly property real y: 2839
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15528;2509:12481"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15528;2509:12481;4189:38496"
+ readonly property string filePath: "light/images/rangeslider-first-handle-disabled.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-first-handle-disabled"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 17661
+ readonly property real y: 2838
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15528;2509:12481;4178:28261"
+ readonly property string filePath: "light/images/rangeslider-groove-disabled.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17642
+ readonly property real y: 2847
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15528;2509:12481;4191:43003"
+ readonly property string filePath: "light/images/rangeslider-second-handle-disabled.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-second-handle-disabled"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 17785
+ readonly property real y: 2838
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15528;2509:12481;4189:38505"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 17672
+ readonly property real y: 2847
+ }
+
+ }
+
+ readonly property QtObject handle_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15526;8624:14526"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background-handle-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17634
+ readonly property real y: 2781
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15526;8624:14525"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem-handle-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15526;8624:14556"
+ readonly property string filePath: "light/images/rangeslider-first-handle-handle-pressed.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-first-handle-handle-pressed"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 17661
+ readonly property real y: 2780
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15526;8624:14529"
+ readonly property string filePath: "light/images/rangeslider-groove-handle-pressed.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove-handle-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17642
+ readonly property real y: 2789
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15526;8624:14627"
+ readonly property string filePath: "light/images/rangeslider-second-handle-handle-pressed.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-second-handle-handle-pressed"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 17785
+ readonly property real y: 2780
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15526;8624:14531"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track-handle-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 17672
+ readonly property real y: 2789
+ }
+
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15524;8624:14397"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17634
+ readonly property real y: 2723
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15524;8624:14396"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15524;8624:14427"
+ readonly property string filePath: "light/images/rangeslider-first-handle-hovered.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-first-handle-hovered"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 17661
+ readonly property real y: 2722
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15524;8624:14400"
+ readonly property string filePath: "light/images/rangeslider-groove-hovered.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17642
+ readonly property real y: 2731
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15524;8624:14506"
+ readonly property string filePath: "light/images/rangeslider-second-handle-hovered.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-second-handle-hovered"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 17785
+ readonly property real y: 2722
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15524;8624:14402"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 17672
+ readonly property real y: 2731
+ }
+
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15522;2509:12436;2509:12419"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 200
+ readonly property real x: 17634
+ readonly property real y: 2665
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15522;2509:12436"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "rangeslider-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject first_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15522;2509:12436;4189:38496"
+ readonly property string filePath: "light/images/rangeslider-first-handle.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-first-handle"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 17661
+ readonly property real y: 2664
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15522;2509:12436;4178:28261"
+ readonly property string filePath: "light/images/rangeslider-groove.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-groove"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 184
+ readonly property real x: 17642
+ readonly property real y: 2673
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property QtObject second_handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15522;2509:12436;4191:43003"
+ readonly property string filePath: "light/images/rangeslider-second-handle.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-second-handle"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 17785
+ readonly property real y: 2664
+ }
+
+ readonly property real spacing: -154
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15522;2509:12436;4189:38505"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "rangeslider-track"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 17672
+ readonly property real y: 2673
+ }
+
+ }
+
+ }
+
+ readonly property QtObject slider: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15554;2506:12695;4200:48590"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22622
+ readonly property real y: 2827.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15554;2506:12695"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem-disabled"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15554;2506:12695;4385:9106"
+ readonly property string filePath: "light/images/slider-groove-disabled.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22630
+ readonly property real y: 2835.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15554;2506:12695;4200:48601"
+ readonly property string filePath: "light/images/slider-handle-disabled.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-handle-disabled"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 22792
+ readonly property real y: 2826.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15554;2506:12695;4200:48597"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22630
+ readonly property real y: 2835.5
+ }
+
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15550;8624:13850"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22622
+ readonly property real y: 2708.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15550;8624:13849"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem-hovered"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15550;8624:13853"
+ readonly property string filePath: "light/images/slider-groove-hovered.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22630
+ readonly property real y: 2716.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15550;8624:13874"
+ readonly property string filePath: "light/images/slider-handle-hovered.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-handle-hovered"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 22792
+ readonly property real y: 2707.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15550;8624:13855"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22630
+ readonly property real y: 2716.5
+ }
+
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15548;2506:12656;4200:48590"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22622
+ readonly property real y: 2649.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15548;2506:12656"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15548;2506:12656;4385:9106"
+ readonly property string filePath: "light/images/slider-groove.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22630
+ readonly property real y: 2657.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15548;2506:12656;4200:48601"
+ readonly property string filePath: "light/images/slider-handle.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-handle"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 22792
+ readonly property real y: 2648.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15548;2506:12656;4200:48597"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22630
+ readonly property real y: 2657.5
+ }
+
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15552;8624:14647"
+ readonly property string filePath: ""
+ readonly property real height: 20
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 224
+ readonly property real x: 22622
+ readonly property real y: 2768.5
+ }
+
+ readonly property real bottomPadding: 2
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15552;8624:14646"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 8
+ readonly property string name: "slider-contentItem-pressed"
+ readonly property real rightPadding: 8
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject groove: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15552;8624:14650"
+ readonly property string filePath: "light/images/slider-groove-pressed.png"
+ readonly property real height: 4
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-groove-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 2
+ readonly property real topShadow: 0
+ readonly property real width: 208
+ readonly property real x: 22630
+ readonly property real y: 2776.5
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15552;8624:14671"
+ readonly property string filePath: "light/images/slider-handle-pressed.png"
+ readonly property real height: 22
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-handle-pressed"
+ readonly property real rightOffset: 9
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 22
+ readonly property real x: 22792
+ readonly property real y: 2767.5
+ }
+
+ readonly property real leftPadding: 8
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 8
+ readonly property real spacing: -208
+ readonly property real topPadding: 2
+ readonly property QtObject track: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15552;8624:14652"
+ readonly property real height: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "slider-track-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 173
+ readonly property real x: 22630
+ readonly property real y: 2776.5
+ }
+
+ }
+
+ }
+
+ readonly property QtObject spinbox: QtObject {
+ readonly property QtObject atlimit: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15571;2766:9577;2526:13406"
+ readonly property string filePath: "light/images/spinbox-background-atlimit.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-atlimit"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24379
+ readonly property real y: 2457.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15571;2766:9577"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-atlimit"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15571;2766:9577;2526:13408;4418:24767"
+ readonly property string filePath: "light/images/spinbox-indicator-down-background-atlimit.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-atlimit"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24471
+ readonly property real y: 2461.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15571;2766:9577;2526:13408;8858:14984"
+ readonly property string filePath: "light/images/spinbox-indicator-down-icon-atlimit.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-atlimit"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24482
+ readonly property real y: 2472.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15571;2766:9577;2526:13412;4418:25668"
+ readonly property string filePath: "light/images/spinbox-indicator-up-background-atlimit.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-atlimit"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24439
+ readonly property real y: 2461.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15571;2766:9577;2526:13412;8858:15141"
+ readonly property string filePath: "light/images/spinbox-indicator-up-icon-atlimit.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-atlimit"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24450
+ readonly property real y: 2472.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15571;2766:9577;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-atlimit"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24391
+ readonly property real y: 2464.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15561;2766:9207;2526:13406"
+ readonly property string filePath: "light/images/spinbox-background-disabled.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24379
+ readonly property real y: 2122.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15561;2766:9207"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-disabled"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15561;2766:9207;2526:13408;4418:24767"
+ readonly property string filePath: "light/images/spinbox-indicator-down-background-disabled.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24471
+ readonly property real y: 2126.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15561;2766:9207;2526:13408;8858:14984"
+ readonly property string filePath: "light/images/spinbox-indicator-down-icon-disabled.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24482
+ readonly property real y: 2137.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15561;2766:9207;2526:13412;4418:25668"
+ readonly property string filePath: "light/images/spinbox-indicator-up-background-disabled.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24439
+ readonly property real y: 2126.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15561;2766:9207;2526:13412;8858:15141"
+ readonly property string filePath: "light/images/spinbox-indicator-up-icon-disabled.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-disabled"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24450
+ readonly property real y: 2137.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15561;2766:9207;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24391
+ readonly property real y: 2129.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject down_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15563;2766:9281;2526:13406"
+ readonly property string filePath: "light/images/spinbox-background-down-hovered.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-down-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24379
+ readonly property real y: 2189.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15563;2766:9281"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-down-hovered"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15563;2766:9281;2526:13408;4418:24767"
+ readonly property string filePath: "light/images/spinbox-indicator-down-background-down-hovered.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-down-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24471
+ readonly property real y: 2193.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15563;2766:9281;2526:13408;8858:14984"
+ readonly property string filePath: "light/images/spinbox-indicator-down-icon-down-hovered.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-down-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24482
+ readonly property real y: 2204.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15563;2766:9281;2526:13412;4418:25668"
+ readonly property string filePath: "light/images/spinbox-indicator-up-background-down-hovered.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-down-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24439
+ readonly property real y: 2193.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15563;2766:9281;2526:13412;8858:15141"
+ readonly property string filePath: "light/images/spinbox-indicator-up-icon-down-hovered.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-down-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24450
+ readonly property real y: 2204.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15563;2766:9281;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-down-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24391
+ readonly property real y: 2196.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject down_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15565;2766:9355;2526:13406"
+ readonly property string filePath: "light/images/spinbox-background-down-pressed.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-down-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24379
+ readonly property real y: 2256.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15565;2766:9355"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-down-pressed"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15565;2766:9355;2526:13408;4418:24767"
+ readonly property string filePath: "light/images/spinbox-indicator-down-background-down-pressed.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-down-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24471
+ readonly property real y: 2260.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15565;2766:9355;2526:13408;8858:14984"
+ readonly property string filePath: "light/images/spinbox-indicator-down-icon-down-pressed.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-down-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24482
+ readonly property real y: 2271.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15565;2766:9355;2526:13412;4418:25668"
+ readonly property string filePath: "light/images/spinbox-indicator-up-background-down-pressed.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-down-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24439
+ readonly property real y: 2260.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15565;2766:9355;2526:13412;8858:15141"
+ readonly property string filePath: "light/images/spinbox-indicator-up-icon-down-pressed.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-down-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24450
+ readonly property real y: 2271.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15565;2766:9355;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-down-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24391
+ readonly property real y: 2263.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15559;2766:9133;2526:13406"
+ readonly property string filePath: "light/images/spinbox-background-hovered.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24379
+ readonly property real y: 2055.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15559;2766:9133"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-hovered"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15559;2766:9133;2526:13408;4418:24767"
+ readonly property string filePath: "light/images/spinbox-indicator-down-background-hovered.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24471
+ readonly property real y: 2059.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15559;2766:9133;2526:13408;8858:14984"
+ readonly property string filePath: "light/images/spinbox-indicator-down-icon-hovered.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24482
+ readonly property real y: 2070.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15559;2766:9133;2526:13412;4418:25668"
+ readonly property string filePath: "light/images/spinbox-indicator-up-background-hovered.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24439
+ readonly property real y: 2059.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15559;2766:9133;2526:13412;8858:15141"
+ readonly property string filePath: "light/images/spinbox-indicator-up-icon-hovered.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24450
+ readonly property real y: 2070.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15559;2766:9133;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24391
+ readonly property real y: 2062.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15557;2766:9059;2526:13406"
+ readonly property string filePath: "light/images/spinbox-background.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24379
+ readonly property real y: 1988.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15557;2766:9059"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15557;2766:9059;2526:13408;4418:24767"
+ readonly property string filePath: "light/images/spinbox-indicator-down-background.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24471
+ readonly property real y: 1992.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15557;2766:9059;2526:13408;8858:14984"
+ readonly property string filePath: "light/images/spinbox-indicator-down-icon.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24482
+ readonly property real y: 2003.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15557;2766:9059;2526:13412;4418:25668"
+ readonly property string filePath: "light/images/spinbox-indicator-up-background.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24439
+ readonly property real y: 1992.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15557;2766:9059;2526:13412;8858:15141"
+ readonly property string filePath: "light/images/spinbox-indicator-up-icon.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24450
+ readonly property real y: 2003.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15557;2766:9059;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24391
+ readonly property real y: 1995.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject up_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15567;2766:9429;2526:13406"
+ readonly property string filePath: "light/images/spinbox-background-up-hovered.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-up-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24379
+ readonly property real y: 2323.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15567;2766:9429"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-up-hovered"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15567;2766:9429;2526:13408;4418:24767"
+ readonly property string filePath: "light/images/spinbox-indicator-down-background-up-hovered.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-up-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24471
+ readonly property real y: 2327.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15567;2766:9429;2526:13408;8858:14984"
+ readonly property string filePath: "light/images/spinbox-indicator-down-icon-up-hovered.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-up-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24482
+ readonly property real y: 2338.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15567;2766:9429;2526:13412;4418:25668"
+ readonly property string filePath: "light/images/spinbox-indicator-up-background-up-hovered.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-up-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24439
+ readonly property real y: 2327.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15567;2766:9429;2526:13412;8858:15141"
+ readonly property string filePath: "light/images/spinbox-indicator-up-icon-up-hovered.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-up-hovered"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24450
+ readonly property real y: 2338.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15567;2766:9429;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-up-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24391
+ readonly property real y: 2330.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject up_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15569;2766:9503;2526:13406"
+ readonly property string filePath: "light/images/spinbox-background-up-pressed.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-background-up-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 124
+ readonly property real x: 24379
+ readonly property real y: 2390.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15569;2766:9503"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "spinbox-contentItem-up-pressed"
+ readonly property real rightPadding: 5
+ readonly property real spacing: 8
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject indicator_down_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15569;2766:9503;2526:13408;4418:24767"
+ readonly property string filePath: "light/images/spinbox-indicator-down-background-up-pressed.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-background-up-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24471
+ readonly property real y: 2394.5
+ }
+
+ readonly property QtObject indicator_down_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15569;2766:9503;2526:13408;8858:14984"
+ readonly property string filePath: "light/images/spinbox-indicator-down-icon-up-pressed.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-down-icon-up-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24482
+ readonly property real y: 2405.25
+ }
+
+ readonly property QtObject indicator_up_background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15569;2766:9503;2526:13412;4418:25668"
+ readonly property string filePath: "light/images/spinbox-indicator-up-background-up-pressed.png"
+ readonly property real height: 26
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-background-up-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 30
+ readonly property real x: 24439
+ readonly property real y: 2394.5
+ }
+
+ readonly property QtObject indicator_up_icon: QtObject {
+ readonly property real bottomOffset: 1
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15569;2766:9503;2526:13412;8858:15141"
+ readonly property string filePath: "light/images/spinbox-indicator-up-icon-up-pressed.png"
+ readonly property real height: 4.50586
+ readonly property real leftOffset: 1
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-indicator-up-icon-up-pressed"
+ readonly property real rightOffset: 1
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 1
+ readonly property real topShadow: 0
+ readonly property real width: 8.00391
+ readonly property real x: 24450
+ readonly property real y: 2405.25
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: true
+ readonly property real rightPadding: 5
+ readonly property real spacing: 64
+ readonly property QtObject textInput: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15569;2766:9503;2526:13381"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "spinbox-textInput-up-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 24391
+ readonly property real y: 2397.5
+ }
+
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject switch_: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15580;2531:14856;4350:34538"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2250.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15580;2531:14856"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15580;2531:14856;4350:34543"
+ readonly property string filePath: "light/images/switch-handle-checked.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-checked"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 6
+ readonly property real topShadow: 0
+ readonly property real width: 14
+ readonly property real x: 25645.5
+ readonly property real y: 2259.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15580;2531:14856;4350:34541"
+ readonly property string filePath: "light/images/switch-handle-background-checked.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2256.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:15580;2531:14856;4350:34542"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-checked"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15580;2531:14856;6761:23654"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2256.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15588;2531:14900;4350:34538"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2454.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15588;2531:14900"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked-disabled"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15588;2531:14900;4350:34543"
+ readonly property string filePath: "light/images/switch-handle-checked-disabled.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-checked-disabled"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 6
+ readonly property real topShadow: 0
+ readonly property real width: 14
+ readonly property real x: 25645.5
+ readonly property real y: 2463.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15588;2531:14900;4350:34541"
+ readonly property string filePath: "light/images/switch-handle-background-checked-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked-disabled"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2460.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:15588;2531:14900;4350:34542"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-checked-disabled"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15588;2531:14900;6761:23654"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2460.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15584;8664:14952"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2352.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15584;8664:14951"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked-hovered"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15584;8664:14975"
+ readonly property string filePath: "light/images/switch-handle-checked-hovered.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 7
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-checked-hovered"
+ readonly property real rightOffset: 6
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 7
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 25644.5
+ readonly property real y: 2360.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15584;8664:14954"
+ readonly property string filePath: "light/images/switch-handle-background-checked-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked-hovered"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2358.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15584;8664:14955"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 2
+ readonly property string name: "switch-handle-contentItem-checked-hovered"
+ readonly property real rightPadding: 2
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15584;8664:14957"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2358.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15586;8664:14801"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2403.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15586;8664:14800"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-checked-pressed"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15586;8664:14824"
+ readonly property string filePath: "light/images/switch-handle-checked-pressed.png"
+ readonly property real height: 16
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-checked-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 7
+ readonly property real topShadow: 0
+ readonly property real width: 19
+ readonly property real x: 25641.5
+ readonly property real y: 2411.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15586;8664:14803"
+ readonly property string filePath: "light/images/switch-handle-background-checked-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-checked-pressed"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2409.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property string alignItems: "MAX"
+ readonly property real bottomPadding: 2
+ readonly property string figmaId: "I2557:15586;8664:14804"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 2
+ readonly property string name: "switch-handle-contentItem-checked-pressed"
+ readonly property real rightPadding: 2
+ readonly property real spacing: 0
+ readonly property real topPadding: 2
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15586;8664:14806"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2409.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15582;2531:14867;2942:5449"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2301.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15582;2531:14867"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-disabled"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15582;2531:14867;2531:14816"
+ readonly property string filePath: "light/images/switch-handle-disabled.png"
+ readonly property real height: 12
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-disabled"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 6
+ readonly property real topShadow: 0
+ readonly property real width: 12
+ readonly property real x: 25626.5
+ readonly property real y: 2311.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15582;2531:14867;2531:14819"
+ readonly property string filePath: "light/images/switch-handle-background-disabled.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-disabled"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2307.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:15582;2531:14867;2531:14811"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-handle-contentItem-disabled"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15582;2531:14867;6761:24226"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2307.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15576;8664:14878"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2148.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15576;8664:14877"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-hovered"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15576;8664:14900"
+ readonly property string filePath: "light/images/switch-handle-hovered.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 7
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-hovered"
+ readonly property real rightOffset: 6
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 7
+ readonly property real topShadow: 0
+ readonly property real width: 14
+ readonly property real x: 25625.5
+ readonly property real y: 2157.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15576;8664:14880"
+ readonly property string filePath: "light/images/switch-handle-background-hovered.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-hovered"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2154.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:15576;8664:14881"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-hovered"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15576;8664:14883"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2154.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15574;2531:14823;2942:5449"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2091.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15574;2531:14823"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 5
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15574;2531:14823;2531:14816"
+ readonly property string filePath: "light/images/switch-handle.png"
+ readonly property real height: 12
+ readonly property real leftOffset: 6
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle"
+ readonly property real rightOffset: 5
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 6
+ readonly property real topShadow: 0
+ readonly property real width: 12
+ readonly property real x: 25626.5
+ readonly property real y: 2101.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15574;2531:14823;2531:14819"
+ readonly property string filePath: "light/images/switch-handle-background.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2097.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:15574;2531:14823;2531:14811"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-handle-contentItem"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15574;2531:14823;6761:24226"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2097.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15578;8664:14715"
+ readonly property string filePath: ""
+ readonly property real height: 32
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 99
+ readonly property real x: 25618.5
+ readonly property real y: 2199.5
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15578;8664:14714"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "switch-contentItem-pressed"
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject handle: QtObject {
+ readonly property real bottomOffset: 6
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15578;8664:14737"
+ readonly property string filePath: "light/images/switch-handle-pressed.png"
+ readonly property real height: 14
+ readonly property real leftOffset: 8
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-pressed"
+ readonly property real rightOffset: 8
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 7
+ readonly property real topShadow: 0
+ readonly property real width: 17
+ readonly property real x: 25625.5
+ readonly property real y: 2208.5
+ }
+
+ readonly property QtObject handle_background: QtObject {
+ readonly property real bottomOffset: 9
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15578;8664:14717"
+ readonly property string filePath: "light/images/switch-handle-background-pressed.png"
+ readonly property real height: 20
+ readonly property real leftOffset: 10
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-handle-background-pressed"
+ readonly property real rightOffset: 10
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 10
+ readonly property real topShadow: 0
+ readonly property real width: 40
+ readonly property real x: 25622.5
+ readonly property real y: 2205.5
+ }
+
+ readonly property QtObject handle_contentItem: QtObject {
+ readonly property real bottomPadding: 3
+ readonly property string figmaId: "I2557:15578;8664:14718"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 3
+ readonly property string name: "switch-handle-contentItem-pressed"
+ readonly property real rightPadding: 3
+ readonly property real spacing: 0
+ readonly property real topPadding: 3
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15578;8664:14720"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "switch-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 2
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 33
+ readonly property real x: 25674.5
+ readonly property real y: 2205.5
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 10
+ readonly property real spacing: 12
+ readonly property real topPadding: 6
+ }
+
+ }
+
+ readonly property QtObject tabbar: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15646;2556:17466;2556:17413"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-background-disabled"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 470
+ readonly property real x: 26266.5
+ readonly property real y: 2847
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:15646;2556:17466"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "tabbar-contentItem-disabled"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property QtObject tabButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15646;2556:17466;2556:17415"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton1-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26270.5
+ readonly property real y: 2851
+ }
+
+ readonly property QtObject tabButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15646;2556:17466;2556:17421"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton2-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26347.5
+ readonly property real y: 2851
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject disabled_footer: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15650;2556:17577;2556:17534"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-background-disabled-footer"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 470
+ readonly property real x: 26267
+ readonly property real y: 2977
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:15650;2556:17577"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "tabbar-contentItem-disabled-footer"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property QtObject tabButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15650;2556:17577;2556:17536"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton1-disabled-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26271
+ readonly property real y: 2981
+ }
+
+ readonly property QtObject tabButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15650;2556:17577;2556:17537"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton2-disabled-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26348
+ readonly property real y: 2981
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15644;2556:17439;2556:17413"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-background"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 470
+ readonly property real x: 26267
+ readonly property real y: 2776
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:15644;2556:17439"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "tabbar-contentItem"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property QtObject tabButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15644;2556:17439;2556:17415"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton1"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26271
+ readonly property real y: 2780
+ }
+
+ readonly property QtObject tabButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15644;2556:17439;2556:17421"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton2"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26348
+ readonly property real y: 2780
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject normal_footer: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15648;2556:17555;2556:17534"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-background-normal-footer"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 470
+ readonly property real x: 26267
+ readonly property real y: 2910
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2557:15648;2556:17555"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "tabbar-contentItem-normal-footer"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 0
+ readonly property QtObject tabButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15648;2556:17555;2556:17536"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton1-normal-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26271
+ readonly property real y: 2914
+ }
+
+ readonly property QtObject tabButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15648;2556:17555;2556:17537"
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbar-tabButton2-normal-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 26348
+ readonly property real y: 2914
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ }
+
+ readonly property QtObject tabbutton: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15633;2556:16919;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-checked"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28142
+ readonly property real y: 1948.5
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:15633;2556:16919"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-checked"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15633;2556:16919;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-checked"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28154
+ readonly property real y: 1958.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15633;2556:16919;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28182
+ readonly property real y: 1958.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15639;2556:16934;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-checked-disabled"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28142
+ readonly property real y: 2149.5
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:15639;2556:16934"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-checked-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15639;2556:16934;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28154
+ readonly property real y: 2159.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15639;2556:16934;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28182
+ readonly property real y: 2159.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15637;2556:16929;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-checked-hovered"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28142
+ readonly property real y: 2082.5
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:15637;2556:16929"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-checked-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15637;2556:16929;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28154
+ readonly property real y: 2092.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15637;2556:16929;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28182
+ readonly property real y: 2092.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15641;2556:16939;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-checked-pressed"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28142
+ readonly property real y: 2216.5
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:15641;2556:16939"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-checked-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15641;2556:16939;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28154
+ readonly property real y: 2226.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15641;2556:16939;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28182
+ readonly property real y: 2226.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15635;2556:16924;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-disabled"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28142
+ readonly property real y: 2023.24
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:15635;2556:16924"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15635;2556:16924;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28154
+ readonly property real y: 2033.24
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15635;2556:16924;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28182
+ readonly property real y: 2033.24
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15629;2556:16909;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-hovered"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28142
+ readonly property real y: 1814.5
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:15629;2556:16909"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15629;2556:16909;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28154
+ readonly property real y: 1824.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15629;2556:16909;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28182
+ readonly property real y: 1824.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15627;2556:16904;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28142
+ readonly property real y: 1747.5
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:15627;2556:16904"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15627;2556:16904;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28154
+ readonly property real y: 1757.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15627;2556:16904;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28182
+ readonly property real y: 1757.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15631;2556:16914;2556:16901"
+ readonly property string filePath: ""
+ readonly property real height: 40
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-background-pressed"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 77
+ readonly property real x: 28142
+ readonly property real y: 1881.5
+ }
+
+ readonly property real bottomPadding: 10
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 10
+ readonly property string figmaId: "I2557:15631;2556:16914"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "tabbutton-contentItem-pressed"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15631;2556:16914;6815:11841"
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-icon-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 20
+ readonly property real x: 28154
+ readonly property real y: 1891.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15631;2556:16914;2556:16898"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "tabbutton-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 28182
+ readonly property real y: 1891.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 12
+ readonly property real spacing: 8
+ readonly property real topPadding: 10
+ }
+
+ }
+
+ readonly property QtObject textarea: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15602;2554:13608;2554:13585"
+ readonly property string filePath: "light/images/textarea-background-disabled.png"
+ readonly property real height: 52
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 202
+ readonly property real x: 30155
+ readonly property real y: 2589
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15602;2554:13608"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textarea-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15602;2554:13608;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30167
+ readonly property real y: 2595
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject focused: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2654:6236;2654:5963;2554:13585"
+ readonly property string filePath: "light/images/textarea-background-focused.png"
+ readonly property real height: 52
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-background-focused"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 202
+ readonly property real x: 30155
+ readonly property real y: 2666
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2654:6236;2654:5963"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textarea-contentItem-focused"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2654:6236;2654:5963;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label-focused"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30167
+ readonly property real y: 2672
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15600;2554:13603;2554:13585"
+ readonly property string filePath: "light/images/textarea-background-hovered.png"
+ readonly property real height: 52
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 202
+ readonly property real x: 30155
+ readonly property real y: 2512
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15600;2554:13603"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textarea-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15600;2554:13603;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30167
+ readonly property real y: 2518
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15598;2554:13588;2554:13585"
+ readonly property string filePath: "light/images/textarea-background.png"
+ readonly property real height: 52
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 202
+ readonly property real x: 30155
+ readonly property real y: 2435
+ }
+
+ readonly property real bottomPadding: 6
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 6
+ readonly property string figmaId: "I2557:15598;2554:13588"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textarea-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 6
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15598;2554:13588;2554:13582"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 40
+ readonly property real leftShadow: 0
+ readonly property string name: "textarea-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 32
+ readonly property real topShadow: 0
+ readonly property real width: 178
+ readonly property real x: 30167
+ readonly property real y: 2441
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 6
+ }
+
+ }
+
+ readonly property QtObject textfield: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15595;2537:15922;2537:15894"
+ readonly property string filePath: "light/images/textfield-background-disabled.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 160
+ readonly property real x: 29361
+ readonly property real y: 1873.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15595;2537:15922"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem-disabled"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15595;2537:15922;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29373
+ readonly property real y: 1878.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject focused: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2644:5967;2644:5955;2537:15894"
+ readonly property string filePath: "light/images/textfield-background-focused.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-background-focused"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 160
+ readonly property real x: 29361
+ readonly property real y: 1942.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2644:5967;2644:5955"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem-focused"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2644:5967;2644:5955;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label-focused"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29373
+ readonly property real y: 1947.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15593;2537:15917;2537:15894"
+ readonly property string filePath: "light/images/textfield-background-hovered.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 160
+ readonly property real x: 29361
+ readonly property real y: 1804.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15593;2537:15917"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem-hovered"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15593;2537:15917;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29373
+ readonly property real y: 1809.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15591;2537:15912;2537:15894"
+ readonly property string filePath: "light/images/textfield-background.png"
+ readonly property real height: 30
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 160
+ readonly property real x: 29361
+ readonly property real y: 1735.5
+ }
+
+ readonly property real bottomPadding: 5
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 5
+ readonly property string figmaId: "I2557:15591;2537:15912"
+ readonly property string layoutMode: "VERTICAL"
+ readonly property real leftPadding: 12
+ readonly property string name: "textfield-contentItem"
+ readonly property real rightPadding: 12
+ readonly property real spacing: 0
+ readonly property real topPadding: 5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15591;2537:15912;2537:15892"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 16
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "textfield-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 1
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 28
+ readonly property real x: 29373
+ readonly property real y: 1740.5
+ }
+
+ readonly property real leftPadding: 12
+ readonly property real rightPadding: 12
+ readonly property real topPadding: 5
+ }
+
+ }
+
+ readonly property QtObject toolbar: QtObject {
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5726;2556:19625;2556:19554"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-background-disabled"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 225
+ readonly property real x: 31349
+ readonly property real y: 2862
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2942:5726;2556:19625"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "toolbar-contentItem-disabled"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property QtObject toolButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5726;2556:19625;2556:19556"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton1-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31353
+ readonly property real y: 2869
+ }
+
+ readonly property QtObject toolButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5726;2556:19625;2556:19562"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton2-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31426
+ readonly property real y: 2869
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject disabled_footer: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5728;2556:19669;2556:19582"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-background-disabled-footer"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 225
+ readonly property real x: 31349
+ readonly property real y: 2996
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2942:5728;2556:19669"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "toolbar-contentItem-disabled-footer"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property QtObject toolButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5728;2556:19669;2556:19584"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton1-disabled-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31353
+ readonly property real y: 3003
+ }
+
+ readonly property QtObject toolButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5728;2556:19669;2556:19585"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton2-disabled-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31426
+ readonly property real y: 3003
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5725;2556:19603;2556:19554"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-background"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 225
+ readonly property real x: 31349
+ readonly property real y: 2795
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2942:5725;2556:19603"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "toolbar-contentItem"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property QtObject toolButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5725;2556:19603;2556:19556"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton1"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31353
+ readonly property real y: 2802
+ }
+
+ readonly property QtObject toolButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5725;2556:19603;2556:19562"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton2"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31426
+ readonly property real y: 2802
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ readonly property QtObject normal_footer: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 0
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5727;2556:19647;2556:19582"
+ readonly property string filePath: ""
+ readonly property real height: 48
+ readonly property real leftOffset: 0
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-background-normal-footer"
+ readonly property real rightOffset: 0
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 0
+ readonly property real topShadow: 0
+ readonly property real width: 225
+ readonly property real x: 31349
+ readonly property real y: 2929
+ }
+
+ readonly property real bottomPadding: 4
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 4
+ readonly property string figmaId: "I2942:5727;2556:19647"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 4
+ readonly property string name: "toolbar-contentItem-normal-footer"
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property real topPadding: 4
+ }
+
+ readonly property real leftPadding: 4
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 4
+ readonly property real spacing: 2
+ readonly property QtObject toolButton1: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5727;2556:19647;2556:19584"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton1-normal-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31353
+ readonly property real y: 2936
+ }
+
+ readonly property QtObject toolButton2: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2942:5727;2556:19647;2556:19585"
+ readonly property real height: 34
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbar-toolButton2-normal-footer"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 31426
+ readonly property real y: 2936
+ }
+
+ readonly property real topPadding: 4
+ }
+
+ }
+
+ readonly property QtObject toolbutton: QtObject {
+ readonly property QtObject checked: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15659;2556:18709;2556:18691"
+ readonly property string filePath: "light/images/toolbutton-background-checked.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-checked"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33127
+ readonly property real y: 1942
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:15659;2556:18709"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-checked"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15659;2556:18709;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-checked"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33138
+ readonly property real y: 1951
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15659;2556:18709;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-checked"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33162
+ readonly property real y: 1949
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject checked_disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15665;2556:18724;2556:18691"
+ readonly property string filePath: "light/images/toolbutton-background-checked-disabled.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-checked-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33127
+ readonly property real y: 2143
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:15665;2556:18724"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-checked-disabled"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15665;2556:18724;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33138
+ readonly property real y: 2152
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15665;2556:18724;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-checked-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33162
+ readonly property real y: 2150
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject checked_hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15663;2556:18719;2556:18691"
+ readonly property string filePath: "light/images/toolbutton-background-checked-hovered.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-checked-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33127
+ readonly property real y: 2076
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:15663;2556:18719"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-checked-hovered"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15663;2556:18719;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33138
+ readonly property real y: 2085
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15663;2556:18719;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-checked-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33162
+ readonly property real y: 2083
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject checked_pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15667;2556:18729;2556:18691"
+ readonly property string filePath: "light/images/toolbutton-background-checked-pressed.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-checked-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33127
+ readonly property real y: 2212.5
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:15667;2556:18729"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-checked-pressed"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15667;2556:18729;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33138
+ readonly property real y: 2221.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15667;2556:18729;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-checked-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33162
+ readonly property real y: 2219.5
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject disabled: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15661;2556:18714;2556:18691"
+ readonly property string filePath: "light/images/toolbutton-background-disabled.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-disabled"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33127
+ readonly property real y: 2009.5
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:15661;2556:18714"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-disabled"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15661;2556:18714;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-disabled"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33138
+ readonly property real y: 2018.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15661;2556:18714;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-disabled"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33162
+ readonly property real y: 2016.5
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject hovered: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15655;2556:18699;2556:18691"
+ readonly property string filePath: "light/images/toolbutton-background-hovered.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-hovered"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33127
+ readonly property real y: 1810.5
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:15655;2556:18699"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-hovered"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15655;2556:18699;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-hovered"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33138
+ readonly property real y: 1819.5
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15655;2556:18699;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-hovered"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33162
+ readonly property real y: 1817.5
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject normal: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15653;2556:18694;2556:18691"
+ readonly property string filePath: ""
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33127
+ readonly property real y: 1741
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:15653;2556:18694"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15653;2556:18694;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33138
+ readonly property real y: 1750
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15653;2556:18694;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33162
+ readonly property real y: 1748
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject pressed: QtObject {
+ readonly property QtObject background: QtObject {
+ readonly property real bottomOffset: 4
+ readonly property real bottomShadow: 0
+ readonly property string exportType: "image"
+ readonly property string figmaId: "I2557:15657;2556:18704;2556:18691"
+ readonly property string filePath: "light/images/toolbutton-background-pressed.png"
+ readonly property real height: 34
+ readonly property real leftOffset: 4
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-background-pressed"
+ readonly property real rightOffset: 4
+ readonly property real rightShadow: 0
+ readonly property real topOffset: 4
+ readonly property real topShadow: 0
+ readonly property real width: 71
+ readonly property real x: 33126
+ readonly property real y: 1877
+ }
+
+ readonly property real bottomPadding: 11
+ readonly property QtObject contentItem: QtObject {
+ readonly property string alignItems: "CENTER"
+ readonly property real bottomPadding: 11
+ readonly property string figmaId: "I2557:15657;2556:18704"
+ readonly property string layoutMode: "HORIZONTAL"
+ readonly property real leftPadding: 11
+ readonly property string name: "toolbutton-contentItem-pressed"
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ readonly property QtObject icon: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15657;2556:18704;8907:14161"
+ readonly property real height: 16
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-icon-pressed"
+ readonly property real rightShadow: 0
+ readonly property real topShadow: 0
+ readonly property real width: 16
+ readonly property real x: 33137
+ readonly property real y: 1886
+ }
+
+ readonly property QtObject label: QtObject {
+ readonly property real bottomShadow: 0
+ readonly property string figmaId: "I2557:15657;2556:18704;4732:16190"
+ readonly property string fontFamily: "Segoe UI"
+ readonly property real fontSize: 14
+ readonly property real height: 20
+ readonly property real leftShadow: 0
+ readonly property string name: "toolbutton-label-pressed"
+ readonly property real rightShadow: 0
+ readonly property real textHAlignment: 4
+ readonly property real textVAlignment: 128
+ readonly property real topShadow: 0
+ readonly property real width: 25
+ readonly property real x: 33161
+ readonly property real y: 1884
+ }
+
+ readonly property real leftPadding: 11
+ readonly property bool mirrored: false
+ readonly property real rightPadding: 11
+ readonly property real spacing: 8
+ readonly property real topPadding: 11
+ }
+
+ }
+
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/Frame.qml b/src/quickcontrols/fluentwinui3/Frame.qml
new file mode 100644
index 0000000000..27af99633e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/Frame.qml
@@ -0,0 +1,34 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Frame {
+ id: control
+
+ implicitWidth: Math.max((background.minimumWidth || implicitBackgroundWidth)
+ + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max((background.minimumHeight || implicitBackgroundHeight)
+ + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: !control.enabled ? "disabled" : "normal";
+ readonly property var config: Config.controls.frame[__currentState] || {}
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/GroupBox.qml b/src/quickcontrols/fluentwinui3/GroupBox.qml
new file mode 100644
index 0000000000..808c6837cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/GroupBox.qml
@@ -0,0 +1,64 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.GroupBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitLabelWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ readonly property real __deltaY: (config.background.y - config.label.y) || 0
+ readonly property real __deltaX: (config.background.x - config.label.x) || 0
+ spacing: (__deltaY - config.label.height) || 0
+
+ topPadding: (config.topPadding || 0) + (spacing >= 0 ? (label.height + spacing) : __deltaY)
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: (config.leftPadding || 0) + (__deltaX >= 0 ? __deltaX : 0)
+ rightPadding: config.rightPadding || 0
+
+ topInset: __deltaY > 0 ? __deltaY : 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: __deltaX > 0 ? __deltaX : 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: [
+ !control.enabled && "disabled",
+ control.enabled && control.hovered && "hovered",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.groupbox[__currentState] || {}
+
+ label: T.Label {
+ x: control.__deltaX > 0 ? 0 : -__deltaX
+ y: control.__deltaY > 0 ? 0 : -__deltaY
+
+ topPadding: control.config.label_contentItem.topPadding || 0
+ leftPadding: control.config.label_contentItem.leftPadding || 0
+ rightPadding: control.config.label_contentItem.rightPadding || 0
+ bottomPadding: control.config.label_contentItem.bottomPadding || 0
+
+ height: Math.max(implicitHeight, config.label.height)
+
+ text: control.title
+ font: control.font
+ color: control.palette.windowText
+ elide: Text.ElideRight
+ horizontalAlignment: control.config.label_text.textHAlignment
+ verticalAlignment: control.config.label_text.textVAlignment
+
+ background: StyleImage {
+ imageConfig: control.config.label_background
+ }
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background.filePath ? control.config.background : Config.controls.frame["normal"].background // fallback to regular frame background
+ height: parent.height - control.topPadding + control.bottomPadding
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/ItemDelegate.qml b/src/quickcontrols/fluentwinui3/ItemDelegate.qml
new file mode 100644
index 0000000000..36e9ca078a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/ItemDelegate.qml
@@ -0,0 +1,87 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ItemDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: config.topPadding || 0 + verticalOffset
+ leftPadding: config.leftPadding || 0 + horizontalOffset
+ rightPadding: config.rightPadding || 0 + horizontalOffset
+ bottomPadding: config.bottomPadding || 0 + verticalOffset
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ icon.width: 16
+ icon.height: 16
+ icon.color: control.down ? control.palette.brightText : control.palette.buttonText
+
+ readonly property int horizontalOffset: 4
+ readonly property int verticalOffset: 2
+
+ readonly property string __currentState: [
+ !control.enabled && "disabled",
+ control.highlighted && "highlighted",
+ control.enabled && !control.down && control.hovered && "hovered",
+ control.down && "pressed"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.itemdelegate[__currentState] || {}
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.icon.color
+ }
+
+ background: Item {
+ implicitWidth: 160
+ implicitHeight: 40
+
+ property Item backgroundImage: StyleImage {
+ parent: control.background
+ imageConfig: control.config.background
+ implicitWidth: parent.width - control.horizontalOffset * 2
+ implicitHeight: parent.height - control.verticalOffset * 2
+ x: control.horizontalOffset
+ y: control.verticalOffset
+ }
+
+ property Rectangle selector: Rectangle {
+ parent: control.background.backgroundImage
+ y: (parent.height - height) / 2
+ width: 3
+ height: (control.highlighted || control.activeFocus)
+ ? control.down ? 10 : 16
+ : 0
+ radius: width * 0.5
+ color: control.palette.accent
+ visible: control.highlighted || control.activeFocus
+
+ Behavior on height {
+ NumberAnimation {
+ duration: 187
+ easing.type: Easing.OutCubic
+ }
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/Popup.qml b/src/quickcontrols/fluentwinui3/Popup.qml
new file mode 100644
index 0000000000..d72d352ba5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/Popup.qml
@@ -0,0 +1,52 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Popup {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: "normal"
+ readonly property var config: Config.controls.popup[__currentState] || {}
+
+ enter: Transition {
+ NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; easing.type: Easing.Linear; duration: 83 }
+ NumberAnimation { property: "scale"; from: control.modal ? 1.05 : 1; to: 1; easing.type: Easing.OutCubic; duration: 167 }
+ }
+
+ exit: Transition {
+ NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; easing.type: Easing.Linear; duration: 83 }
+ NumberAnimation { property: "scale"; from: 1; to: control.modal ? 1.05 : 1; easing.type: Easing.OutCubic; duration: 167 }
+ }
+
+ background: StyleImage {
+ implicitWidth: 320
+ implicitHeight: 72
+ imageConfig: control.config.background
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: "#4D000000"
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: "transparent"
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/ProgressBar.qml b/src/quickcontrols/fluentwinui3/ProgressBar.qml
new file mode 100644
index 0000000000..513f624e04
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/ProgressBar.qml
@@ -0,0 +1,117 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.Effects
+
+T.ProgressBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: [
+ !control.enabled && "disabled",
+ control.indeterminate && "indeterminate"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.progressbar[__currentState] || {}
+
+ contentItem: Item {
+ implicitWidth: control.indeterminate ? parent.availableWidth : progress.implicitWidth
+ implicitHeight: control.indeterminate ? control.config.track.height : progress.implicitHeight
+ scale: control.mirrored ? -1 : 1
+ clip: control.indeterminate
+
+ readonly property Rectangle progress: Rectangle {
+ x: control.background.groove?.x - 1
+ y: control.background.groove?.y - 1
+ parent: control.contentItem
+ visible: !control.indeterminate && control.value
+ implicitWidth: control.config.track.width
+ implicitHeight: control.config.track.height
+ width: control.position * parent.width
+ height: control.config.track.height
+ radius: control.config.track.height * 0.5
+ color: control.palette.accent
+ }
+
+ readonly property Rectangle animatedProgress: Rectangle {
+ parent: control.contentItem
+ implicitWidth: parent.width
+ implicitHeight: control.config.track.height
+ radius: control.config.track.height * 0.5
+ clip: true
+ visible: false
+ color: "transparent"
+ Rectangle {
+ width: 0.5 * parent.width
+ height: control.config.track.height
+ radius: control.config.track.height * 0.5
+ color: control.palette.accent
+ SequentialAnimation on x {
+ loops: Animation.Infinite
+ running: control.indeterminate && control.visible
+ NumberAnimation {
+ from: -control.contentItem.animatedProgress.width
+ to: control.contentItem.width
+ easing.type: Easing.InOutCubic
+ duration: control.width * 8
+ }
+ NumberAnimation {
+ from: -control.contentItem.animatedProgress.width * 0.5
+ to: control.contentItem.width
+ easing.type: Easing.InOutCubic
+ duration: control.width * 5
+ }
+ }
+ }
+ }
+
+ readonly property Rectangle mask: Rectangle {
+ parent: control.contentItem
+ width: control.availableWidth
+ height: control.contentItem.animatedProgress.height
+ radius: control.contentItem.animatedProgress.radius
+ visible: false
+ color: control.palette.accent
+ layer.enabled: true
+ antialiasing: false
+ }
+
+ MultiEffect {
+ visible: control.indeterminate
+ source: control.contentItem.animatedProgress
+ width: control.contentItem.animatedProgress.width
+ height: control.contentItem.animatedProgress.height
+ maskEnabled: true
+ maskSource: control.contentItem.mask
+ }
+ }
+
+ background: Item {
+ implicitWidth: groove.width
+ property Item groove: StyleImage {
+ imageConfig: control.config.groove
+ visible: !control.indeterminate
+ parent: control.background
+ height: implicitHeight
+ width: parent.width
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/RadioButton.qml b/src/quickcontrols/fluentwinui3/RadioButton.qml
new file mode 100644
index 0000000000..ee1ed8d4ad
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/RadioButton.qml
@@ -0,0 +1,59 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.RadioButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: [
+ control.checked && "checked",
+ !control.enabled && "disabled",
+ control.enabled && !control.down && control.hovered && "hovered",
+ control.down && "pressed"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.radiobutton[__currentState] || {}
+ readonly property bool mirroredIndicator: control.mirrored !== (config.mirrored || false)
+
+ indicator: Image {
+ x: control.text ? (control.mirroredIndicator ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ source: Qt.resolvedUrl(control.config.indicator.filePath)
+ }
+
+ contentItem: Text {
+ leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0
+ rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0
+
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/RangeSlider.qml b/src/quickcontrols/fluentwinui3/RangeSlider.qml
new file mode 100644
index 0000000000..73b157bae0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/RangeSlider.qml
@@ -0,0 +1,197 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.RangeSlider {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ first.implicitHandleWidth + leftPadding + rightPadding,
+ second.implicitHandleWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ first.implicitHandleHeight + topPadding + bottomPadding,
+ second.implicitHandleHeight + topPadding + bottomPadding)
+
+ topPadding: horizontal ? config.topPadding : config.leftPadding || 0
+ leftPadding: horizontal ? config.leftPadding : config.bottomPadding || 0
+ rightPadding: horizontal ? config.rightPadding : config.topPadding || 0
+ bottomPadding: horizontal ? config.bottomPadding : config.rightPadding || 0
+
+ readonly property string __controlState: [
+ !control.enabled && "disabled",
+ control.enabled && control.hovered && !(first.pressed || second.pressed) && "hovered",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.rangeslider[__controlState] || {}
+
+ readonly property real __steps: Math.abs(to - from) / stepSize
+ readonly property bool __isDiscrete: stepSize >= Number.EPSILON
+ && Math.abs(Math.round(__steps) - __steps) < Number.EPSILON
+
+ property string __firstHandleState: [
+ !control.enabled && "disabled",
+ first.hovered && !first.pressed && "hovered",
+ first.pressed && "handle_pressed",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var firstHandleConfig: Config.controls.rangeslider[__firstHandleState] || {}
+
+ property string __secondHandleState: [
+ !control.enabled && "disabled",
+ second.hovered && !second.pressed && "hovered",
+ second.pressed && "handle_pressed",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var secondHandleConfig: Config.controls.rangeslider[__secondHandleState] || {}
+
+ first.handle: StyleImage {
+ x: Math.round(control.leftPadding + (control.horizontal
+ ? control.first.visualPosition * (control.availableWidth - width)
+ : (control.availableWidth - width) / 2))
+ y: Math.round(control.topPadding + (control.horizontal
+ ? (control.availableHeight - height) / 2
+ : control.first.visualPosition * (control.availableHeight - height)))
+
+ imageConfig: control.firstHandleConfig.first_handle
+
+ property Rectangle indicator: Rectangle {
+ property real diameter: !control.enabled ? 10 : control.first.pressed ? 8 : control.first.hovered ? 14 : 10
+ parent: control.first.handle
+ width: diameter
+ height: diameter
+ radius: diameter * 0.5
+ x: (control.secondHandleConfig.first_handle.width - width) / 2
+ y: (control.secondHandleConfig.first_handle.height - height) / 2
+ color: control.first.pressed
+ ? Application.styleHints.colorScheme == Qt.Light ? "#CC005FB8" : "#CC60CDFF"// AccentFillColorTertiary
+ : control.palette.accent
+ Behavior on diameter {
+ // From WindowsUI 3 Animation Values
+ NumberAnimation {
+ duration: 167
+ easing.type: Easing.OutCubic
+ }
+ }
+ }
+ }
+
+ second.handle: StyleImage {
+ x: Math.round(control.leftPadding + (control.horizontal
+ ? control.second.visualPosition * (control.availableWidth - width)
+ : (control.availableWidth - width) / 2))
+ y: Math.round(control.topPadding + (control.horizontal
+ ? (control.availableHeight - height) / 2
+ : control.second.visualPosition * (control.availableHeight - height)))
+
+ imageConfig: control.secondHandleConfig.second_handle
+
+ property Rectangle indicator: Rectangle {
+ property real diameter: control.second.pressed ? 8 : control.second.hovered ? 14 : 10
+ parent: control.second.handle
+ width: diameter
+ height: diameter
+ radius: diameter * 0.5
+ x: (control.secondHandleConfig.second_handle.width - width) / 2
+ y: (control.secondHandleConfig.second_handle.height - height) / 2
+ color: control.second.pressed
+ ? Application.styleHints.colorScheme == Qt.Light ? "#CC005FB8" : "#CC60CDFF"// AccentFillColorTertiary
+ : control.palette.accent
+ Behavior on diameter {
+ // From WindowsUI 3 Animation Values
+ NumberAnimation{
+ duration: 167
+ easing.type: Easing.OutCubic
+ }
+ }
+ }
+ }
+
+ background: Item {
+ implicitWidth: control.horizontal
+ ? (_background.implicitWidth || _background.groove.implicitWidth)
+ : (_background.implicitHeight || _background.groove.implicitHeight)
+ implicitHeight: control.horizontal
+ ? (_background.implicitHeight || _background.groove.implicitHeight)
+ : (_background.implicitWidth || _background.groove.implicitWidth)
+
+ property Item _background: StyleImage {
+ parent: control.background
+ width: parent.width
+ height: parent.width
+ imageConfig: control.config.background
+
+ property Item groove: StyleImage {
+ parent: control.background._background
+ x: control.leftPadding - control.leftInset + (control.horizontal
+ ? control.firstHandleConfig.first_handle.width / 2
+ : (control.availableWidth - width) / 2)
+ y: control.topPadding - control.rightInset + (control.horizontal
+ ? ((control.availableHeight - height) / 2)
+ : control.firstHandleConfig.first_handle.height / 2)
+
+ width: control.horizontal
+ ? control.availableWidth
+ - (control.firstHandleConfig.first_handle.width / 2) - (control.secondHandleConfig.second_handle.width / 2)
+ : implicitWidth
+ height: control.horizontal
+ ? implicitHeight
+ : control.availableHeight
+ - (control.firstHandleConfig.first_handle.width / 2) - (control.secondHandleConfig.second_handle.width / 2)
+ imageConfig: control.config.groove
+ horizontal: control.horizontal
+
+ property Rectangle track: Rectangle {
+ parent: control.background._background.groove
+ x: control.horizontal ? parent.width * control.first.position : 0
+ y: control.horizontal ? 0 : parent.height - (parent.height * control.second.position)
+ implicitWidth: control.horizontal ? control.config.track.width : control.config.track.height
+ implicitHeight: control.horizontal ? control.config.track.height : control.config.track.width
+ width: control.horizontal
+ ? parent.width * (control.second.position - control.first.position)
+ : parent.width
+ height: control.horizontal
+ ? parent.height
+ : parent.height * (control.second.position - control.first.position)
+ radius: control.config.track.height * 0.5
+ color: control.palette.accent
+ }
+ }
+
+ property Repeater ticksTop: Repeater {
+ parent: control.background._background.groove
+ model: control.__isDiscrete ? Math.floor(control.__steps) + 1 : 0
+ delegate: Rectangle {
+ width: control.horizontal ? 1 : 4
+ height: control.horizontal ? 4 : 1
+ x: control.horizontal
+ ? 6 + index * (parent.width - 2 * 6 - width) / (control.background._background.ticksTop.model - 1)
+ : -4 - width
+ y: control.horizontal
+ ? -4 - height
+ : 6 + index * (parent.height - 2 * 6 - height) / (control.background._background.ticksTop.model - 1)
+ color: Application.styleHints.colorScheme == Qt.Light ? "#9C000000" : "#9AFFFFFF"
+
+ required property int index
+ }
+ }
+
+ property Repeater ticksBottom: Repeater {
+ parent: control.background._background.groove
+ model: control.__isDiscrete ? Math.floor(control.__steps) + 1 : 0
+ delegate: Rectangle {
+ width: control.horizontal ? 1 : 4
+ height: control.horizontal ? 4 : 1
+ x: control.horizontal
+ ? 6 + index * (parent.width - 2 * 6 - width) / (control.background._background.ticksBottom.model - 1)
+ : parent.width + 4
+ y: control.horizontal
+ ? parent.height + 4
+ : 6 + index * (parent.height - 2 * 6 - height) / (control.background._background.ticksBottom.model - 1)
+ color: Application.styleHints.colorScheme == Qt.Light ? "#9C000000" : "#9AFFFFFF"
+
+ required property int index
+ }
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/Slider.qml b/src/quickcontrols/fluentwinui3/Slider.qml
new file mode 100644
index 0000000000..2ebdc616ed
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/Slider.qml
@@ -0,0 +1,144 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Slider {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitHandleWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitHandleHeight + topPadding + bottomPadding)
+
+ topPadding: horizontal ? config.topPadding : config.leftPadding || 0
+ leftPadding: horizontal ? config.leftPadding : config.bottomPadding || 0
+ rightPadding: horizontal ? config.rightPadding : config.topPadding || 0
+ bottomPadding: horizontal ? config.bottomPadding : config.rightPadding || 0
+
+ readonly property string __currentState: [
+ !control.enabled && "disabled",
+ control.enabled && !control.pressed && control.hovered && "hovered",
+ control.pressed && "pressed"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.slider[__currentState] || {}
+
+ readonly property real __steps: Math.abs(to - from) / stepSize
+ readonly property bool __isDiscrete: stepSize >= Number.EPSILON
+ && Math.abs(Math.round(__steps) - __steps) < Number.EPSILON
+
+ handle: StyleImage {
+ x: Math.round(control.leftPadding + (control.horizontal
+ ? control.visualPosition * (control.availableWidth - width)
+ : (control.availableWidth - width) / 2))
+ y: Math.round(control.topPadding + (control.horizontal
+ ? (control.availableHeight - height) / 2
+ : control.visualPosition * (control.availableHeight - height)))
+
+ imageConfig: control.config.handle
+
+ property Rectangle indicator: Rectangle {
+ property real diameter: !control.enabled ? 10 : control.pressed ? 8 : control.hovered ? 14 : 10
+ parent: control.handle
+ width: diameter
+ height: diameter
+ radius: diameter * 0.5
+ x: (control.config.handle.width - width) / 2
+ y: (control.config.handle.height - height) / 2
+ color: control.pressed
+ ? Application.styleHints.colorScheme == Qt.Light ? "#CC005FB8" : "#CC60CDFF"// AccentFillColorTertiary
+ : control.palette.accent
+ Behavior on diameter {
+ // From WindowsUI 3 Animation Values
+ NumberAnimation{
+ duration: 167
+ easing.type: Easing.OutCubic
+ }
+ }
+ }
+ }
+
+ background: Item {
+ implicitWidth: control.horizontal
+ ? (_background.implicitWidth || _background.groove.implicitWidth)
+ : (_background.implicitHeight || _background.groove.implicitHeight)
+ implicitHeight: control.horizontal
+ ? (_background.implicitHeight || _background.groove.implicitHeight)
+ : (_background.implicitWidth || _background.groove.implicitWidth)
+
+ property Item _background: StyleImage {
+ parent: control.background
+ width: parent.width
+ height: parent.height
+ imageConfig: control.config.background
+
+ property Item groove: StyleImage {
+ parent: control.background._background
+ x: control.leftPadding - control.leftInset + (control.horizontal
+ ? control.config.handle.width / 2
+ : (control.availableWidth - width) / 2)
+ y: control.topPadding - control.topInset + (control.horizontal
+ ? ((control.availableHeight - height) / 2)
+ : control.config.handle.height / 2)
+
+ width: control.horizontal
+ ? control.availableWidth - control.config.handle.width
+ : implicitWidth
+ height: control.horizontal
+ ? implicitHeight
+ : control.availableHeight - control.config.handle.width
+ imageConfig: control.config.groove
+ horizontal: control.horizontal
+
+ property Rectangle track: Rectangle {
+ parent: control.background._background.groove
+ y: control.horizontal ? 0 : parent.height - (parent.height * control.position)
+ implicitWidth: control.horizontal ? control.config.track.width : control.config.track.height
+ implicitHeight: control.horizontal ? control.config.track.height : control.config.track.width
+ width: control.horizontal ? parent.width * control.position : parent.width
+ height: control.horizontal ? parent.height : parent.height * control.position
+ radius: control.config.track.height * 0.5
+ color: control.palette.accent
+ }
+ }
+
+ property Repeater ticksTop: Repeater {
+ parent: control.background._background.groove
+ model: control.__isDiscrete ? Math.floor(control.__steps) + 1 : 0
+ delegate: Rectangle {
+ width: control.horizontal ? 1 : 4
+ height: control.horizontal ? 4 : 1
+ x: control.horizontal
+ ? 6 + index * (parent.width - 2 * 6 - width) / (control.background._background.ticksTop.model - 1)
+ : -4 - width
+ y: control.horizontal
+ ? -4 - height
+ : 6 + index * (parent.height - 2 * 6 - height) / (control.background._background.ticksTop.model - 1)
+ color: Application.styleHints.colorScheme == Qt.Light ? "#9C000000" : "#9AFFFFFF"
+
+ required property int index
+ }
+ }
+
+ property Repeater ticksBottom: Repeater {
+ parent: control.background._background.groove
+ model: control.__isDiscrete ? Math.floor(control.__steps) + 1 : 0
+ delegate: Rectangle {
+ width: control.horizontal ? 1 : 4
+ height: control.horizontal ? 4 : 1
+ x: control.horizontal
+ ? 6 + index * (parent.width - 2 * 6 - width) / (control.background._background.ticksBottom.model - 1)
+ : parent.width + 4
+ y: control.horizontal
+ ? parent.height + 4
+ : 6 + index * (parent.height - 2 * 6 - height) / (control.background._background.ticksBottom.model - 1)
+ color: Application.styleHints.colorScheme == Qt.Light ? "#9C000000" : "#9AFFFFFF"
+
+ required property int index
+ }
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/SpinBox.qml b/src/quickcontrols/fluentwinui3/SpinBox.qml
new file mode 100644
index 0000000000..ada068e912
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/SpinBox.qml
@@ -0,0 +1,106 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.Controls.FluentWinUI3.impl
+
+T.SpinBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentItem.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ up.implicitIndicatorHeight, down.implicitIndicatorHeight)
+
+ property string __controlState: [
+ enabled && (down.hovered || down.pressed) && "down",
+ enabled && (up.hovered || up.pressed) && !(down.hovered || down.pressed) && "up",
+ enabled && (hovered || down.hovered || up.hovered) && !(down.pressed || up.pressed) && "hovered",
+ enabled && (down.pressed || up.pressed) && "pressed",
+ !enabled && "disabled"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.spinbox[__controlState] || {}
+ readonly property var downConfig: value == from ? Config.controls.spinbox["atlimit"] : config
+ readonly property var upConfig: value == to ? Config.controls.spinbox["atlimit"] : config
+
+ spacing: config.contentItem.spacing || 0
+ leftPadding: ((!mirrored ? config.leftPadding : config.rightPadding) || 0) + (mirrored ? (up.indicator ? up.indicator.width * 2 : 0) : 0)
+ rightPadding: ((!mirrored ? config.rightPadding : config.leftPadding) || 0) + (!mirrored ? (up.indicator ? up.indicator.width * 2 : 0) : 0)
+ topPadding: config.topPadding || 0
+ bottomPadding: config?.bottomPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ validator: IntValidator {
+ locale: control.locale.name
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
+ }
+
+ contentItem: TextInput {
+ clip: width < implicitWidth
+ text: control.displayText
+ opacity: control.enabled ? 1 : 0.3
+
+ font: control.font
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ horizontalAlignment: control.mirrored ? Text.AlignRight : Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+
+ readOnly: !control.editable
+ validator: control.validator
+ inputMethodHints: control.inputMethodHints
+ }
+
+ down.indicator: StyleImage {
+ x: !control.mirrored ? control.up.indicator ? (control.up.indicator.x - width) : 0
+ : control.config.rightPadding
+ y: control.topPadding
+ height: control.availableHeight
+ imageConfig: control.downConfig.indicator_down_background
+
+ StyleImage {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ imageConfig: control.downConfig.indicator_down_icon
+ }
+ }
+
+ up.indicator: StyleImage {
+ x: control.mirrored ? control.config.rightPadding + (control.down.indicator ? control.down.indicator.width : 0)
+ : control.width - width - control.config.rightPadding
+ y: control.topPadding
+ height: control.availableHeight
+ imageConfig: control.upConfig.indicator_up_background
+
+ StyleImage {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ imageConfig: control.upConfig.indicator_up_icon
+ }
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ Item {
+ visible: control.activeFocus
+ width: parent.width
+ height: 2
+ y: parent.height - height
+ FocusStroke {
+ width: parent.width
+ height: parent.height
+ radius: control.config.background.bottomOffset
+ color: control.palette.accent
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/StyleImage.qml b/src/quickcontrols/fluentwinui3/StyleImage.qml
new file mode 100644
index 0000000000..f67b52268b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/StyleImage.qml
@@ -0,0 +1,54 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+
+// This item will resize the child image in such a way that any drop shadow
+// or blur (or other effects) will be drawn outside its own bounds.
+// The effect is that users of this item won't have to take e.g shadows
+// into account when positioning it, as such effects will only be visual, and
+// not be a part of the geometry.
+
+Item {
+ id: root
+ implicitWidth: horizontal ? imageConfig.width : imageConfig.height
+ implicitHeight: horizontal ? imageConfig.height : imageConfig.width
+
+ required property var imageConfig
+
+ // Set horizontal to false if you want the image to be rotated 90 degrees
+ // Doing so will rotate the image, but also flip it, to make sure that
+ // the shadow ends up on the correct side. The implicit geometry of the
+ // item will also be adjusted to match the rotated image.
+ property bool horizontal: true
+
+ // The minimum size of the image should be at least 1px tall and wide, even without any offsets
+ property real minimumWidth: Math.max(1, imageConfig.leftOffset + imageConfig.rightOffset)
+ property real minimumHeight: Math.max(1, imageConfig.topOffset + imageConfig.bottomOffset)
+
+ BorderImage {
+ x: -imageConfig.leftShadow
+ y: -imageConfig.topShadow
+ width: Math.max(root.minimumWidth, (root.horizontal ? root.width : root.height))
+ + imageConfig.leftShadow + imageConfig.rightShadow
+ height: Math.max(root.minimumHeight, (root.horizontal ? root.height : root.width))
+ + imageConfig.topShadow + imageConfig.bottomShadow
+ source: Qt.resolvedUrl(imageConfig.filePath)
+
+ border {
+ top: Math.min(height / 2, imageConfig.topOffset + imageConfig.topShadow)
+ left: Math.min(width / 2, imageConfig.leftOffset + imageConfig.leftShadow)
+ bottom: Math.min(height / 2, imageConfig.bottomOffset + imageConfig.bottomShadow)
+ right: Math.min(width / 2, imageConfig.rightOffset + imageConfig.rightShadow)
+ }
+
+ transform: [
+ Rotation {
+ angle: root.horizontal ? 0 : 90
+ },
+ Scale {
+ xScale: root.horizontal ? 1 : -1
+ }
+ ]
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/Switch.qml b/src/quickcontrols/fluentwinui3/Switch.qml
new file mode 100644
index 0000000000..7821af4d85
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/Switch.qml
@@ -0,0 +1,81 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Switch {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding,
+ implicitIndicatorWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: control.text ? config.topPadding || 0 : 0
+ leftPadding: control.text ? config.leftPadding || 0 : 0
+ rightPadding: control.text ? config.rightPadding || 0 : 0
+ bottomPadding: control.text ? config.bottomPadding || 0 : 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: [
+ control.checked && "checked",
+ !control.enabled && "disabled",
+ control.enabled && !control.down && control.hovered && "hovered",
+ control.down && "pressed"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.switch_[__currentState] || {}
+ readonly property bool mirroredIndicator: control.mirrored !== (config.mirrored || false)
+
+ indicator: Item {
+ x: control.text ? (control.mirroredIndicator ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ // If handleBackground is not generated, use the size of the handle
+ implicitWidth: handleBackground.width > 0 ? handleBackground.width : handleBackground.handle.width * 2
+ implicitHeight: handleBackground.height > 0 ? handleBackground.height : handleBackground.handle.height
+
+ property Item handleBackground: StyleImage {
+ parent: control.indicator
+ imageConfig: control.config.handle_background
+
+ property Item handle: StyleImage {
+ parent: control.indicator.handleBackground
+ x: control.config.handle_contentItem.leftPadding
+ + (control.visualPosition * (parent.width - width
+ - control.config.handle_contentItem.leftPadding
+ - control.config.handle_contentItem.rightPadding))
+ y: control.config.handle_contentItem.topPadding
+
+ imageConfig: control.config.handle
+
+ Behavior on x {
+ enabled: !control.down
+ SmoothedAnimation {
+ velocity: 200
+ }
+ }
+ }
+ }
+ }
+
+ contentItem: Text {
+ leftPadding: control.indicator && !control.mirroredIndicator ? control.indicator.width + control.spacing : 0
+ rightPadding: control.indicator && control.mirroredIndicator ? control.indicator.width + control.spacing : 0
+
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/TabBar.qml b/src/quickcontrols/fluentwinui3/TabBar.qml
new file mode 100644
index 0000000000..09b0068c2c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/TabBar.qml
@@ -0,0 +1,52 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.TabBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: position === TabBar.Header
+ ? (enabled ? "normal" : "disabled")
+ : (enabled ? "normal_footer" : "disabled_footer")
+ readonly property var config: Config.controls.tabbar[__currentState] || {}
+
+ contentItem: ListView {
+ model: control.contentModel
+ currentIndex: control.currentIndex
+
+ spacing: control.config.spacing
+ orientation: ListView.Horizontal
+ boundsBehavior: Flickable.StopAtBounds
+ flickableDirection: Flickable.AutoFlickIfNeeded
+ snapMode: ListView.SnapToItem
+
+ highlightMoveDuration: 0
+ highlightRangeMode: ListView.ApplyRange
+ preferredHighlightBegin: 48
+ preferredHighlightEnd: width - 48
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/TabButton.qml b/src/quickcontrols/fluentwinui3/TabButton.qml
new file mode 100644
index 0000000000..7ea5d90366
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/TabButton.qml
@@ -0,0 +1,85 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.TabButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ icon.width: 16
+ icon.height: 16
+ icon.color: control.down
+ ? Qt.styleHints.colorScheme == Qt.Light? "#72000000" : "#87FFFFFF" // TextFillColorTertiary
+ : control.hovered ? control.palette.brightText : control.palette.buttonText
+
+ readonly property string __currentState: [
+ checked && "checked",
+ !enabled && "disabled",
+ enabled && !down && hovered && "hovered",
+ down && "pressed"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.tabbutton[__currentState] || {}
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.config.label.textVAlignment | control.config.label.textHAlignment
+ text: control.text
+ font: control.font
+ icon: control.icon
+ color: control.down
+ ? Qt.styleHints.colorScheme == Qt.Light? "#72000000" : "#87FFFFFF" // TextFillColorTertiary
+ : control.hovered ? control.palette.brightText : control.palette.buttonText
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ property Rectangle selector: Rectangle {
+ parent: control.background
+ x: (parent.width - implicitWidth) / 2
+ y: parent.height - height
+ height: 3
+ implicitWidth: 16
+ radius: height * 0.5
+ color: control.palette.accent
+ visible: control.checked
+
+ states: State {
+ name: "checked"
+ when: control.checked
+ PropertyChanges {
+ target: control.background.selector
+ width: 16
+ }
+ }
+
+ transitions: Transition {
+ to: "checked"
+ ParallelAnimation {
+ NumberAnimation { target: control.background.selector; property: "opacity"; from: 0; to: 1; easing.type: Easing.Linear; duration: 83}
+ NumberAnimation { target: control.background.selector; property: "scale"; from: 0.33; to: 1; easing.type: Easing.InOutCubic; duration: 167}
+ }
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/TextArea.qml b/src/quickcontrols/fluentwinui3/TextArea.qml
new file mode 100644
index 0000000000..91cce0fb43
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/TextArea.qml
@@ -0,0 +1,73 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.FluentWinUI3.impl
+
+T.TextArea {
+ id: control
+
+ implicitWidth: implicitBackgroundWidth + leftInset + rightInset
+ || Math.max(contentWidth, placeholder.implicitWidth) + leftPadding + rightPadding
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding,
+ placeholder.implicitHeight + topPadding + bottomPadding)
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ placeholderTextColor: control.palette.placeholderText
+ verticalAlignment: Text.AlignVCenter
+
+ readonly property string __currentState: [
+ !enabled && "disabled",
+ activeFocus && "focused",
+ enabled && !activeFocus && hovered && "hovered",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.textarea[__currentState] || {}
+
+ PlaceholderText {
+ id: placeholder
+ x: control.leftPadding
+ y: control.topPadding
+ width: control.width - (control.leftPadding + control.rightPadding)
+ height: control.height - (control.topPadding + control.bottomPadding)
+
+ text: control.placeholderText
+ font: control.font
+ color: control.placeholderTextColor
+ verticalAlignment: control.verticalAlignment
+ horizontalAlignment: control.horizontalAlignment
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ Item{
+ visible: control.activeFocus
+ width: parent.width
+ height: 2
+ y: parent.height - height
+ FocusStroke {
+ width: parent.width
+ height: parent.height
+ radius: control.config.background.bottomOffset
+ color: control.palette.accent
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/TextField.qml b/src/quickcontrols/fluentwinui3/TextField.qml
new file mode 100644
index 0000000000..c8979922a8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/TextField.qml
@@ -0,0 +1,73 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.FluentWinUI3.impl
+
+T.TextField {
+ id: control
+
+ implicitWidth: implicitBackgroundWidth + leftInset + rightInset
+ || Math.max(contentWidth, placeholder.implicitWidth) + leftPadding + rightPadding
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding,
+ placeholder.implicitHeight + topPadding + bottomPadding)
+
+ readonly property string __currentState: [
+ !enabled && "disabled",
+ activeFocus && "focused",
+ enabled && !activeFocus && hovered && "hovered",
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.textfield[__currentState] || {}
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ placeholderTextColor: control.palette.placeholderText
+ verticalAlignment: Text.AlignVCenter
+
+ PlaceholderText {
+ id: placeholder
+ x: control.leftPadding
+ y: control.topPadding
+ width: control.width - (control.leftPadding + control.rightPadding)
+ height: control.height - (control.topPadding + control.bottomPadding)
+
+ text: control.placeholderText
+ font: control.font
+ color: control.placeholderTextColor
+ verticalAlignment: control.verticalAlignment
+ horizontalAlignment: control.horizontalAlignment
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ Item{
+ visible: control.activeFocus
+ width: parent.width
+ height: 2
+ y: parent.height - height
+ FocusStroke {
+ width: parent.width
+ height: parent.height
+ radius: control.config.background.bottomOffset
+ color: control.palette.accent
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/ToolBar.qml b/src/quickcontrols/fluentwinui3/ToolBar.qml
new file mode 100644
index 0000000000..97fe41c335
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/ToolBar.qml
@@ -0,0 +1,35 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.ToolBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: position === ToolBar.Header
+ ? (enabled ? "normal" : "disabled")
+ : (enabled ? "normal_footer" : "disabled_footer")
+ readonly property var config: Config.controls.toolbar[__currentState] || {}
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/ToolButton.qml b/src/quickcontrols/fluentwinui3/ToolButton.qml
new file mode 100644
index 0000000000..6d863961b4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/ToolButton.qml
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ToolButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ spacing: config.spacing || 0
+
+ topPadding: config.topPadding || 0
+ bottomPadding: config.bottomPadding || 0
+ leftPadding: config.leftPadding || 0
+ rightPadding: config.rightPadding || 0
+
+ topInset: -config.topInset || 0
+ bottomInset: -config.bottomInset || 0
+ leftInset: -config.leftInset || 0
+ rightInset: -config.rightInset || 0
+
+ readonly property string __currentState: [
+ control.checked && "checked",
+ !control.enabled && "disabled",
+ control.enabled && !control.down && control.hovered && "hovered",
+ down && "pressed"
+ ].filter(Boolean).join("_") || "normal"
+ readonly property var config: Config.controls.toolbutton[__currentState] || {}
+
+ icon.width: config.icon.width
+ icon.height: config.icon.height
+ icon.color: (control.checked || control.highlighted)
+ ? (control.down ? (Qt.styleHints.colorScheme == Qt.Light ? "#7FFFFFFF" : "#80000000") //textOnAccentSecondary
+ : control.palette.highlightedText)
+ : (control.down ? control.palette.brightText : control.palette.buttonText)
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.icon.color
+ }
+
+ background: StyleImage {
+ imageConfig: control.config.background
+ }
+}
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled.png
new file mode 100644
index 0000000000..7adf82bbae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..8294092b83
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..dd0123069f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered.png
new file mode 100644
index 0000000000..0475ad0b56
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..ac0d9937e7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..2c1220cec8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed.png
new file mode 100644
index 0000000000..de34367740
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..67c77bbbfd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..312489af68
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked.png
new file mode 100644
index 0000000000..096bb351d9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked@2x.png
new file mode 100644
index 0000000000..78a4036dca
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked@3x.png
new file mode 100644
index 0000000000..7bd2870284
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled.png
new file mode 100644
index 0000000000..2e683e1279
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@2x.png
new file mode 100644
index 0000000000..47f1925bf3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@3x.png
new file mode 100644
index 0000000000..86adaf82d8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered.png
new file mode 100644
index 0000000000..3f9b62a19a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@2x.png
new file mode 100644
index 0000000000..fcffe7ec03
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@3x.png
new file mode 100644
index 0000000000..3d7bb7d8ec
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed.png
new file mode 100644
index 0000000000..4d1ead28ff
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@2x.png
new file mode 100644
index 0000000000..cbbde10933
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@3x.png
new file mode 100644
index 0000000000..4dd1fe2475
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background.png b/src/quickcontrols/fluentwinui3/dark/images/button-background.png
new file mode 100644
index 0000000000..6b421ea77f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background@2x.png
new file mode 100644
index 0000000000..ab14be9cc7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/button-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/button-background@3x.png
new file mode 100644
index 0000000000..be62222aa7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/button-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled.png
new file mode 100644
index 0000000000..51875ef456
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@2x.png
new file mode 100644
index 0000000000..da6c369391
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@3x.png
new file mode 100644
index 0000000000..3237492196
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered.png
new file mode 100644
index 0000000000..782b2a68de
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..0dc5055479
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..139335118f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed.png
new file mode 100644
index 0000000000..76970066ee
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..0509f4d664
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..556455107a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked.png
new file mode 100644
index 0000000000..403a1e1024
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@2x.png
new file mode 100644
index 0000000000..4de05c6ae5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@3x.png
new file mode 100644
index 0000000000..b15eb6cad9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked.png
new file mode 100644
index 0000000000..dbe1078410
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@2x.png
new file mode 100644
index 0000000000..f2b8f27295
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@3x.png
new file mode 100644
index 0000000000..9ce7c8694c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled-partiallyChecked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled.png
new file mode 100644
index 0000000000..9ddaed9b31
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@2x.png
new file mode 100644
index 0000000000..3da6cc9855
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@3x.png
new file mode 100644
index 0000000000..a4dd2cc4bd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked.png
new file mode 100644
index 0000000000..e68c8c955b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@2x.png
new file mode 100644
index 0000000000..78428a678f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@3x.png
new file mode 100644
index 0000000000..a794fe8d22
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered-partiallyChecked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered.png
new file mode 100644
index 0000000000..5c57f70d33
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@2x.png
new file mode 100644
index 0000000000..7ec3a4c89b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@3x.png
new file mode 100644
index 0000000000..e135f3c80c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed.png
new file mode 100644
index 0000000000..c3fc742a7e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@2x.png
new file mode 100644
index 0000000000..d7d53072fd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@3x.png
new file mode 100644
index 0000000000..5c7de6da3b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked.png
new file mode 100644
index 0000000000..9f17c19e0f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@2x.png
new file mode 100644
index 0000000000..8c0aa879d3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@3x.png
new file mode 100644
index 0000000000..f35230ff18
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-partiallyChecked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed.png
new file mode 100644
index 0000000000..9d6772b4cc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@2x.png
new file mode 100644
index 0000000000..8028f68b45
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@3x.png
new file mode 100644
index 0000000000..19ed4c69c0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator.png
new file mode 100644
index 0000000000..f51009e79c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@2x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@2x.png
new file mode 100644
index 0000000000..c63e5b63b8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@3x.png b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@3x.png
new file mode 100644
index 0000000000..573d31cba9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/checkbox-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-disabled.png
new file mode 100644
index 0000000000..d4b2f4d76c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-disabled@2x.png
new file mode 100644
index 0000000000..a29d6360d7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-disabled@3x.png
new file mode 100644
index 0000000000..9c00282dd6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-focused.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-focused.png
new file mode 100644
index 0000000000..65e8d06209
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-focused.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-focused@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-focused@2x.png
new file mode 100644
index 0000000000..82bd672dd2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-focused@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-focused@3x.png
new file mode 100644
index 0000000000..74e12bbf1c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered-open.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered-open.png
new file mode 100644
index 0000000000..2d19e254cc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered-open@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered-open@2x.png
new file mode 100644
index 0000000000..f804610fea
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered-open@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered-open@3x.png
new file mode 100644
index 0000000000..2777c436de
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered.png
new file mode 100644
index 0000000000..2d19e254cc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered@2x.png
new file mode 100644
index 0000000000..f804610fea
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered@3x.png
new file mode 100644
index 0000000000..2777c436de
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open-pressed.png
new file mode 100644
index 0000000000..40750e82c9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open-pressed@2x.png
new file mode 100644
index 0000000000..d099e925cc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open-pressed@3x.png
new file mode 100644
index 0000000000..77ffba3a35
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open.png
new file mode 100644
index 0000000000..65e8d06209
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open@2x.png
new file mode 100644
index 0000000000..82bd672dd2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open@3x.png
new file mode 100644
index 0000000000..74e12bbf1c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-pressed.png
new file mode 100644
index 0000000000..40750e82c9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-pressed@2x.png
new file mode 100644
index 0000000000..d099e925cc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-pressed@3x.png
new file mode 100644
index 0000000000..77ffba3a35
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background.png
new file mode 100644
index 0000000000..65e8d06209
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background@2x.png
new file mode 100644
index 0000000000..82bd672dd2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-background@3x.png
new file mode 100644
index 0000000000..74e12bbf1c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-disabled.png
new file mode 100644
index 0000000000..1850dea24e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-disabled@2x.png
new file mode 100644
index 0000000000..b4a699df1e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-disabled@3x.png
new file mode 100644
index 0000000000..2586605bc1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-focused.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-focused.png
new file mode 100644
index 0000000000..1850dea24e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-focused.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-focused@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-focused@2x.png
new file mode 100644
index 0000000000..b4a699df1e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-focused@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-focused@3x.png
new file mode 100644
index 0000000000..2586605bc1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered-open.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered-open.png
new file mode 100644
index 0000000000..1850dea24e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered-open@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered-open@2x.png
new file mode 100644
index 0000000000..b4a699df1e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered-open@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered-open@3x.png
new file mode 100644
index 0000000000..2586605bc1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered.png
new file mode 100644
index 0000000000..1850dea24e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered@2x.png
new file mode 100644
index 0000000000..b4a699df1e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered@3x.png
new file mode 100644
index 0000000000..2586605bc1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open-pressed.png
new file mode 100644
index 0000000000..1850dea24e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open-pressed@2x.png
new file mode 100644
index 0000000000..b4a699df1e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open-pressed@3x.png
new file mode 100644
index 0000000000..2586605bc1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open.png
new file mode 100644
index 0000000000..1850dea24e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open@2x.png
new file mode 100644
index 0000000000..b4a699df1e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open@3x.png
new file mode 100644
index 0000000000..2586605bc1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-pressed.png
new file mode 100644
index 0000000000..1850dea24e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-pressed@2x.png
new file mode 100644
index 0000000000..b4a699df1e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-pressed@3x.png
new file mode 100644
index 0000000000..2586605bc1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator.png
new file mode 100644
index 0000000000..1850dea24e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator@2x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator@2x.png
new file mode 100644
index 0000000000..b4a699df1e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator@3x.png b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator@3x.png
new file mode 100644
index 0000000000..2586605bc1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/combobox-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-hovered-open.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-hovered-open.png
new file mode 100644
index 0000000000..a2a3ed90d8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-hovered-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-hovered-open@2x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-hovered-open@2x.png
new file mode 100644
index 0000000000..80be6948ec
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-hovered-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-hovered-open@3x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-hovered-open@3x.png
new file mode 100644
index 0000000000..447d885c2e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-hovered-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open-pressed.png
new file mode 100644
index 0000000000..a2a3ed90d8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open-pressed@2x.png
new file mode 100644
index 0000000000..80be6948ec
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open-pressed@3x.png
new file mode 100644
index 0000000000..447d885c2e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open.png
new file mode 100644
index 0000000000..a2a3ed90d8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open@2x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open@2x.png
new file mode 100644
index 0000000000..80be6948ec
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open@3x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open@3x.png
new file mode 100644
index 0000000000..447d885c2e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-background-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-hovered-open.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-hovered-open.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-hovered-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-hovered-open@2x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-hovered-open@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-hovered-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-hovered-open@3x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-hovered-open@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-hovered-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open-pressed.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open-pressed@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open-pressed@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open@2x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open@3x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-indicator-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-hovered-open.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-hovered-open.png
new file mode 100644
index 0000000000..2499baaf2e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-hovered-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-hovered-open@2x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-hovered-open@2x.png
new file mode 100644
index 0000000000..2ff5f0e8dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-hovered-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-hovered-open@3x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-hovered-open@3x.png
new file mode 100644
index 0000000000..1795e52a6a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-hovered-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open-pressed.png
new file mode 100644
index 0000000000..2499baaf2e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open-pressed@2x.png
new file mode 100644
index 0000000000..2ff5f0e8dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open-pressed@3x.png
new file mode 100644
index 0000000000..1795e52a6a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open.png
new file mode 100644
index 0000000000..2499baaf2e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open@2x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open@2x.png
new file mode 100644
index 0000000000..2ff5f0e8dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open@3x.png b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open@3x.png
new file mode 100644
index 0000000000..1795e52a6a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/editablecombobox-popup-background-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled.png
new file mode 100644
index 0000000000..09051cd629
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..69956edb26
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..691501df4f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered.png
new file mode 100644
index 0000000000..5121a5f4c0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..14f0e3bc3f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..a7ca4257f8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed.png
new file mode 100644
index 0000000000..986c9b62ce
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..b51e3b015a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..a30bc0e244
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked.png
new file mode 100644
index 0000000000..9d5d449785
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@2x.png
new file mode 100644
index 0000000000..9985ca61bf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@3x.png
new file mode 100644
index 0000000000..a532880e8d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled.png
new file mode 100644
index 0000000000..d38a2945ec
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@2x.png
new file mode 100644
index 0000000000..68574ca6c5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@3x.png
new file mode 100644
index 0000000000..54833f0a79
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered.png
new file mode 100644
index 0000000000..07f1a48c79
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@2x.png
new file mode 100644
index 0000000000..9433445903
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@3x.png
new file mode 100644
index 0000000000..f1aa2b58d4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed.png
new file mode 100644
index 0000000000..21275c76c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@2x.png
new file mode 100644
index 0000000000..eb001f6e95
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@3x.png
new file mode 100644
index 0000000000..7550d7af77
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/flatbutton-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/frame-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/frame-background-disabled.png
new file mode 100644
index 0000000000..044a484e1c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/frame-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/frame-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/frame-background-disabled@2x.png
new file mode 100644
index 0000000000..4d3e52592b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/frame-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/frame-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/frame-background-disabled@3x.png
new file mode 100644
index 0000000000..3182ab6a62
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/frame-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/frame-background.png b/src/quickcontrols/fluentwinui3/dark/images/frame-background.png
new file mode 100644
index 0000000000..044a484e1c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/frame-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/frame-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/frame-background@2x.png
new file mode 100644
index 0000000000..4d3e52592b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/frame-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/frame-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/frame-background@3x.png
new file mode 100644
index 0000000000..3182ab6a62
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/frame-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-hovered.png
new file mode 100644
index 0000000000..c1130ce8b7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-hovered@2x.png
new file mode 100644
index 0000000000..5c2ca550bd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-hovered@3x.png
new file mode 100644
index 0000000000..92d64b4f92
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-pressed.png
new file mode 100644
index 0000000000..453412c23b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-pressed@2x.png
new file mode 100644
index 0000000000..5f2cbf8baa
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-pressed@3x.png
new file mode 100644
index 0000000000..738c4ad912
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted.png
new file mode 100644
index 0000000000..453412c23b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted@2x.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted@2x.png
new file mode 100644
index 0000000000..5f2cbf8baa
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted@3x.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted@3x.png
new file mode 100644
index 0000000000..738c4ad912
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-highlighted@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-hovered.png
new file mode 100644
index 0000000000..453412c23b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-hovered@2x.png
new file mode 100644
index 0000000000..5f2cbf8baa
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-hovered@3x.png
new file mode 100644
index 0000000000..738c4ad912
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-pressed.png
new file mode 100644
index 0000000000..c1130ce8b7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-pressed@2x.png
new file mode 100644
index 0000000000..5c2ca550bd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-pressed@3x.png
new file mode 100644
index 0000000000..92d64b4f92
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/itemdelegate-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/popup-background.png b/src/quickcontrols/fluentwinui3/dark/images/popup-background.png
new file mode 100644
index 0000000000..2be99c53bc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/popup-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/popup-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/popup-background@2x.png
new file mode 100644
index 0000000000..cc696f21e3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/popup-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/popup-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/popup-background@3x.png
new file mode 100644
index 0000000000..40d499eadf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/popup-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled.png
new file mode 100644
index 0000000000..c4a8916446
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@2x.png
new file mode 100644
index 0000000000..31cde58066
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@3x.png
new file mode 100644
index 0000000000..cc1aa71758
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove.png
new file mode 100644
index 0000000000..c7ba3d6a64
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@2x.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@2x.png
new file mode 100644
index 0000000000..d2134559a2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@3x.png b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@3x.png
new file mode 100644
index 0000000000..5be9cff56e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/progressbar-groove@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled.png
new file mode 100644
index 0000000000..bede00df2e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@2x.png
new file mode 100644
index 0000000000..48e0d653f7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@3x.png
new file mode 100644
index 0000000000..f4197aefa6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered.png
new file mode 100644
index 0000000000..c7a80d1950
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..1d967f62c8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..ce18b4dd48
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed.png
new file mode 100644
index 0000000000..8214ae0382
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..5b5f3c6dd1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..42e3779ae2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked.png
new file mode 100644
index 0000000000..905524743c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@2x.png
new file mode 100644
index 0000000000..e5ec6207bb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@3x.png
new file mode 100644
index 0000000000..df43c37131
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled.png
new file mode 100644
index 0000000000..81664eebee
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@2x.png
new file mode 100644
index 0000000000..24432b453d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@3x.png
new file mode 100644
index 0000000000..e2d77d49d7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered.png
new file mode 100644
index 0000000000..d41c1269b0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@2x.png
new file mode 100644
index 0000000000..38713114ce
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@3x.png
new file mode 100644
index 0000000000..d1a2b95f57
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed.png
new file mode 100644
index 0000000000..5a3b5dc669
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@2x.png
new file mode 100644
index 0000000000..b264c4bc8e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@3x.png
new file mode 100644
index 0000000000..8f5984d5ba
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator.png
new file mode 100644
index 0000000000..0ee4bdd3bc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@2x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@2x.png
new file mode 100644
index 0000000000..ecaf91b2b7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@3x.png b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@3x.png
new file mode 100644
index 0000000000..cf12731708
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/radiobutton-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled.png
new file mode 100644
index 0000000000..61063b3c1d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@2x.png
new file mode 100644
index 0000000000..67b4b314be
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@3x.png
new file mode 100644
index 0000000000..a0503f6f09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed.png
new file mode 100644
index 0000000000..61063b3c1d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@2x.png
new file mode 100644
index 0000000000..67b4b314be
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@3x.png
new file mode 100644
index 0000000000..a0503f6f09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered.png
new file mode 100644
index 0000000000..cf5f72f106
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@2x.png
new file mode 100644
index 0000000000..247d3d870c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@3x.png
new file mode 100644
index 0000000000..325e21e9c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle.png
new file mode 100644
index 0000000000..cf5f72f106
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@2x.png
new file mode 100644
index 0000000000..247d3d870c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@3x.png
new file mode 100644
index 0000000000..325e21e9c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-first-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled.png
new file mode 100644
index 0000000000..045b2ec08b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@2x.png
new file mode 100644
index 0000000000..6916b75992
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@3x.png
new file mode 100644
index 0000000000..e867a49937
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed.png
new file mode 100644
index 0000000000..d0d1b5700f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@2x.png
new file mode 100644
index 0000000000..6c3a04a15c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@3x.png
new file mode 100644
index 0000000000..5d69d4b991
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered.png
new file mode 100644
index 0000000000..d0d1b5700f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@2x.png
new file mode 100644
index 0000000000..6c3a04a15c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@3x.png
new file mode 100644
index 0000000000..5d69d4b991
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove.png
new file mode 100644
index 0000000000..d0d1b5700f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@2x.png
new file mode 100644
index 0000000000..6c3a04a15c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@3x.png
new file mode 100644
index 0000000000..5d69d4b991
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-groove@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled.png
new file mode 100644
index 0000000000..61063b3c1d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@2x.png
new file mode 100644
index 0000000000..67b4b314be
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@3x.png
new file mode 100644
index 0000000000..a0503f6f09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed.png
new file mode 100644
index 0000000000..61063b3c1d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@2x.png
new file mode 100644
index 0000000000..67b4b314be
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@3x.png
new file mode 100644
index 0000000000..a0503f6f09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered.png
new file mode 100644
index 0000000000..cf5f72f106
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@2x.png
new file mode 100644
index 0000000000..247d3d870c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@3x.png
new file mode 100644
index 0000000000..325e21e9c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle.png
new file mode 100644
index 0000000000..cf5f72f106
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@2x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@2x.png
new file mode 100644
index 0000000000..247d3d870c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@3x.png b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@3x.png
new file mode 100644
index 0000000000..325e21e9c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/rangeslider-second-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled.png
new file mode 100644
index 0000000000..3160859956
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@2x.png
new file mode 100644
index 0000000000..a680350fdd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@3x.png
new file mode 100644
index 0000000000..000dcfc999
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered.png
new file mode 100644
index 0000000000..8e011e1abb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@2x.png
new file mode 100644
index 0000000000..636896f973
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@3x.png
new file mode 100644
index 0000000000..bcc655e1ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed.png
new file mode 100644
index 0000000000..8e011e1abb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@2x.png
new file mode 100644
index 0000000000..636896f973
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@3x.png
new file mode 100644
index 0000000000..bcc655e1ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove.png
new file mode 100644
index 0000000000..8e011e1abb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove@2x.png
new file mode 100644
index 0000000000..636896f973
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-groove@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-groove@3x.png
new file mode 100644
index 0000000000..bcc655e1ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-groove@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled.png
new file mode 100644
index 0000000000..61063b3c1d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@2x.png
new file mode 100644
index 0000000000..67b4b314be
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@3x.png
new file mode 100644
index 0000000000..a0503f6f09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered.png
new file mode 100644
index 0000000000..cf5f72f106
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@2x.png
new file mode 100644
index 0000000000..247d3d870c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@3x.png
new file mode 100644
index 0000000000..325e21e9c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed.png
new file mode 100644
index 0000000000..61063b3c1d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@2x.png
new file mode 100644
index 0000000000..67b4b314be
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@3x.png
new file mode 100644
index 0000000000..a0503f6f09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle.png
new file mode 100644
index 0000000000..cf5f72f106
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle@2x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle@2x.png
new file mode 100644
index 0000000000..247d3d870c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/slider-handle@3x.png b/src/quickcontrols/fluentwinui3/dark/images/slider-handle@3x.png
new file mode 100644
index 0000000000..325e21e9c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/slider-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-atlimit.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-atlimit.png
new file mode 100644
index 0000000000..9681c3a51a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-atlimit.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-atlimit@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-atlimit@2x.png
new file mode 100644
index 0000000000..fa753b7c0b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-atlimit@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-atlimit@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-atlimit@3x.png
new file mode 100644
index 0000000000..ff17e40fc3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-atlimit@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-disabled.png
new file mode 100644
index 0000000000..989077dfc0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-disabled@2x.png
new file mode 100644
index 0000000000..cb5199f4cc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-disabled@3x.png
new file mode 100644
index 0000000000..4df5c29c9b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-hovered.png
new file mode 100644
index 0000000000..9681c3a51a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-hovered@2x.png
new file mode 100644
index 0000000000..fa753b7c0b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-hovered@3x.png
new file mode 100644
index 0000000000..ff17e40fc3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-pressed.png
new file mode 100644
index 0000000000..9681c3a51a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-pressed@2x.png
new file mode 100644
index 0000000000..fa753b7c0b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-pressed@3x.png
new file mode 100644
index 0000000000..ff17e40fc3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-down-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-hovered.png
new file mode 100644
index 0000000000..028c0e409f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-hovered@2x.png
new file mode 100644
index 0000000000..b9a73a6744
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-hovered@3x.png
new file mode 100644
index 0000000000..6a2ffd4457
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-hovered.png
new file mode 100644
index 0000000000..9681c3a51a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-hovered@2x.png
new file mode 100644
index 0000000000..fa753b7c0b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-hovered@3x.png
new file mode 100644
index 0000000000..ff17e40fc3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-pressed.png
new file mode 100644
index 0000000000..9681c3a51a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-pressed@2x.png
new file mode 100644
index 0000000000..fa753b7c0b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-pressed@3x.png
new file mode 100644
index 0000000000..ff17e40fc3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background-up-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background.png
new file mode 100644
index 0000000000..9681c3a51a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background@2x.png
new file mode 100644
index 0000000000..fa753b7c0b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background@3x.png
new file mode 100644
index 0000000000..ff17e40fc3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-atlimit.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-atlimit.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-atlimit.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-atlimit@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-atlimit@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-atlimit@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-atlimit@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-atlimit@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-atlimit@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-disabled.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-disabled@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-disabled@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-hovered.png
new file mode 100644
index 0000000000..1c283456e8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-hovered@2x.png
new file mode 100644
index 0000000000..50139dcfdb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-hovered@3x.png
new file mode 100644
index 0000000000..bf3363addc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-pressed.png
new file mode 100644
index 0000000000..1c283456e8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-pressed@2x.png
new file mode 100644
index 0000000000..50139dcfdb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-pressed@3x.png
new file mode 100644
index 0000000000..bf3363addc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-down-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-hovered.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-hovered@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-hovered@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-hovered.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-hovered@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-hovered@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-pressed.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-pressed@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-pressed@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background-up-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-atlimit.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-atlimit.png
new file mode 100644
index 0000000000..6029935b34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-atlimit.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-atlimit@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-atlimit@2x.png
new file mode 100644
index 0000000000..291ab6c4ec
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-atlimit@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-atlimit@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-atlimit@3x.png
new file mode 100644
index 0000000000..d6fdbdc7fb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-atlimit@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-disabled.png
new file mode 100644
index 0000000000..6029935b34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-disabled@2x.png
new file mode 100644
index 0000000000..291ab6c4ec
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-disabled@3x.png
new file mode 100644
index 0000000000..d6fdbdc7fb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-hovered.png
new file mode 100644
index 0000000000..f08fdcd15d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-hovered@2x.png
new file mode 100644
index 0000000000..56e706e6e8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-hovered@3x.png
new file mode 100644
index 0000000000..020e47c5cd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-pressed.png
new file mode 100644
index 0000000000..9326a07b8e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-pressed@2x.png
new file mode 100644
index 0000000000..d203438544
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-pressed@3x.png
new file mode 100644
index 0000000000..0f22114275
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-down-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-hovered.png
new file mode 100644
index 0000000000..f08fdcd15d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-hovered@2x.png
new file mode 100644
index 0000000000..56e706e6e8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-hovered@3x.png
new file mode 100644
index 0000000000..020e47c5cd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-hovered.png
new file mode 100644
index 0000000000..f08fdcd15d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-hovered@2x.png
new file mode 100644
index 0000000000..56e706e6e8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-hovered@3x.png
new file mode 100644
index 0000000000..020e47c5cd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-pressed.png
new file mode 100644
index 0000000000..f08fdcd15d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-pressed@2x.png
new file mode 100644
index 0000000000..56e706e6e8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-pressed@3x.png
new file mode 100644
index 0000000000..020e47c5cd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon-up-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon.png
new file mode 100644
index 0000000000..f08fdcd15d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon@2x.png
new file mode 100644
index 0000000000..56e706e6e8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon@3x.png
new file mode 100644
index 0000000000..020e47c5cd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-down-icon@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-atlimit.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-atlimit.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-atlimit.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-atlimit@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-atlimit@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-atlimit@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-atlimit@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-atlimit@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-atlimit@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-disabled.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-disabled@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-disabled@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-hovered.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-hovered@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-hovered@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-pressed.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-pressed@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-pressed@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-down-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-hovered.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-hovered@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-hovered@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-hovered.png
new file mode 100644
index 0000000000..1c283456e8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-hovered@2x.png
new file mode 100644
index 0000000000..50139dcfdb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-hovered@3x.png
new file mode 100644
index 0000000000..bf3363addc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-pressed.png
new file mode 100644
index 0000000000..1c283456e8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-pressed@2x.png
new file mode 100644
index 0000000000..50139dcfdb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-pressed@3x.png
new file mode 100644
index 0000000000..bf3363addc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background-up-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-atlimit.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-atlimit.png
new file mode 100644
index 0000000000..739a881723
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-atlimit.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-atlimit@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-atlimit@2x.png
new file mode 100644
index 0000000000..d1d3f7a22e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-atlimit@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-atlimit@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-atlimit@3x.png
new file mode 100644
index 0000000000..a0811313bc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-atlimit@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-disabled.png
new file mode 100644
index 0000000000..739a881723
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-disabled@2x.png
new file mode 100644
index 0000000000..d1d3f7a22e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-disabled@3x.png
new file mode 100644
index 0000000000..a0811313bc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-hovered.png
new file mode 100644
index 0000000000..af8b040a78
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-hovered@2x.png
new file mode 100644
index 0000000000..df10d3c451
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-hovered@3x.png
new file mode 100644
index 0000000000..2d034035dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-pressed.png
new file mode 100644
index 0000000000..af8b040a78
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-pressed@2x.png
new file mode 100644
index 0000000000..df10d3c451
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-pressed@3x.png
new file mode 100644
index 0000000000..2d034035dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-down-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-hovered.png
new file mode 100644
index 0000000000..af8b040a78
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-hovered@2x.png
new file mode 100644
index 0000000000..df10d3c451
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-hovered@3x.png
new file mode 100644
index 0000000000..2d034035dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-hovered.png
new file mode 100644
index 0000000000..af8b040a78
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-hovered@2x.png
new file mode 100644
index 0000000000..df10d3c451
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-hovered@3x.png
new file mode 100644
index 0000000000..2d034035dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-pressed.png
new file mode 100644
index 0000000000..4906342b9d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-pressed@2x.png
new file mode 100644
index 0000000000..47b4e4f14b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-pressed@3x.png
new file mode 100644
index 0000000000..dfa798fb61
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon-up-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon.png
new file mode 100644
index 0000000000..af8b040a78
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon@2x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon@2x.png
new file mode 100644
index 0000000000..df10d3c451
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon@3x.png b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon@3x.png
new file mode 100644
index 0000000000..2d034035dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/spinbox-indicator-up-icon@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled.png
new file mode 100644
index 0000000000..3847e54311
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..36d7cd2d14
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..492feeff72
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered.png
new file mode 100644
index 0000000000..520af09580
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..0d14c010e6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..babf0ed2d4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed.png
new file mode 100644
index 0000000000..9017264f63
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..c91b75f41e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..e1360f4963
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked.png
new file mode 100644
index 0000000000..4e22fd08fe
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@2x.png
new file mode 100644
index 0000000000..94d05aba49
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@3x.png
new file mode 100644
index 0000000000..33a6b39ab5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled.png
new file mode 100644
index 0000000000..67bcb723d3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@2x.png
new file mode 100644
index 0000000000..659e00542e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@3x.png
new file mode 100644
index 0000000000..8f7aa12f03
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered.png
new file mode 100644
index 0000000000..49eaaf2e4e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@2x.png
new file mode 100644
index 0000000000..c0cce54cff
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@3x.png
new file mode 100644
index 0000000000..be9bd9c0de
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed.png
new file mode 100644
index 0000000000..75130db41a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@2x.png
new file mode 100644
index 0000000000..ec72adf408
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@3x.png
new file mode 100644
index 0000000000..721859b8c3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background.png
new file mode 100644
index 0000000000..6d750ef23f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@2x.png
new file mode 100644
index 0000000000..0b0fe38c41
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@3x.png
new file mode 100644
index 0000000000..25032770dd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled.png
new file mode 100644
index 0000000000..81c7e996cd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@2x.png
new file mode 100644
index 0000000000..392a6f8f5a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@3x.png
new file mode 100644
index 0000000000..f422cabeb0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered.png
new file mode 100644
index 0000000000..dcf678415a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@2x.png
new file mode 100644
index 0000000000..54e5aeeea6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@3x.png
new file mode 100644
index 0000000000..02ddaa912d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed.png
new file mode 100644
index 0000000000..3effc502d8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@2x.png
new file mode 100644
index 0000000000..c6cd3ad522
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@3x.png
new file mode 100644
index 0000000000..e139b9e24a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked.png
new file mode 100644
index 0000000000..a4fd9a986d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@2x.png
new file mode 100644
index 0000000000..62c12162f2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@3x.png
new file mode 100644
index 0000000000..aff32fb2c4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled.png
new file mode 100644
index 0000000000..9ff180bec0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@2x.png
new file mode 100644
index 0000000000..4ebfdd2572
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@3x.png
new file mode 100644
index 0000000000..7019635058
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered.png
new file mode 100644
index 0000000000..3a7acdc5ee
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@2x.png
new file mode 100644
index 0000000000..e454ae78b9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@3x.png
new file mode 100644
index 0000000000..fd403d225b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed.png
new file mode 100644
index 0000000000..e270313ca2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@2x.png
new file mode 100644
index 0000000000..717ac3e6c9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@3x.png
new file mode 100644
index 0000000000..010db03b21
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle.png
new file mode 100644
index 0000000000..c95cdad0ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle@2x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle@2x.png
new file mode 100644
index 0000000000..236a14b5e1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/switch-handle@3x.png b/src/quickcontrols/fluentwinui3/dark/images/switch-handle@3x.png
new file mode 100644
index 0000000000..a4a8186ce8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/switch-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled.png
new file mode 100644
index 0000000000..62b2429862
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@2x.png
new file mode 100644
index 0000000000..ede013c7e5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@3x.png
new file mode 100644
index 0000000000..da3c10ca52
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused.png
new file mode 100644
index 0000000000..6ff65a8b2f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@2x.png
new file mode 100644
index 0000000000..52fa05d463
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@3x.png
new file mode 100644
index 0000000000..39874e0a1e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered.png
new file mode 100644
index 0000000000..62b2429862
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@2x.png
new file mode 100644
index 0000000000..ede013c7e5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@3x.png
new file mode 100644
index 0000000000..da3c10ca52
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background.png
new file mode 100644
index 0000000000..62b2429862
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background@2x.png
new file mode 100644
index 0000000000..ede013c7e5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textarea-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textarea-background@3x.png
new file mode 100644
index 0000000000..da3c10ca52
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textarea-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled.png
new file mode 100644
index 0000000000..5107682beb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@2x.png
new file mode 100644
index 0000000000..d558d2a921
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@3x.png
new file mode 100644
index 0000000000..cbe201ffe4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused.png
new file mode 100644
index 0000000000..f8e1eba7e1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@2x.png
new file mode 100644
index 0000000000..f6ccfeedab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@3x.png
new file mode 100644
index 0000000000..1b198cd47a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered.png
new file mode 100644
index 0000000000..86f1093ca8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@2x.png
new file mode 100644
index 0000000000..ad01750e42
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@3x.png
new file mode 100644
index 0000000000..d6fc5f9ead
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background.png
new file mode 100644
index 0000000000..b528edb07a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background@2x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background@2x.png
new file mode 100644
index 0000000000..6af33796bc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/textfield-background@3x.png b/src/quickcontrols/fluentwinui3/dark/images/textfield-background@3x.png
new file mode 100644
index 0000000000..968daa96c6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/textfield-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-disabled.png
new file mode 100644
index 0000000000..0e17e612b4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..33605497e4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..2ff55b535d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-hovered.png
new file mode 100644
index 0000000000..75d2fac6ca
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..cc2473e4f1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..4200b29d52
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-pressed.png
new file mode 100644
index 0000000000..0d5d6c9a14
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..99ec97a2ca
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..a4d542b2c3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked.png
new file mode 100644
index 0000000000..e657d2f133
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked@2x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked@2x.png
new file mode 100644
index 0000000000..be11df6637
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked@3x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked@3x.png
new file mode 100644
index 0000000000..3e441bacfa
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-disabled.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-disabled.png
new file mode 100644
index 0000000000..9d292c4415
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-disabled@2x.png
new file mode 100644
index 0000000000..32af78bc8c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-disabled@3x.png
new file mode 100644
index 0000000000..a543a36720
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-hovered.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-hovered.png
new file mode 100644
index 0000000000..f9db93fc55
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-hovered@2x.png
new file mode 100644
index 0000000000..f6fbb3b1c0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-hovered@3x.png
new file mode 100644
index 0000000000..3fe9e9fc3b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-pressed.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-pressed.png
new file mode 100644
index 0000000000..cc4f541696
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-pressed@2x.png
new file mode 100644
index 0000000000..ef38d62f67
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-pressed@3x.png
new file mode 100644
index 0000000000..6945314496
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/dark/images/toolbutton-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/impl/CMakeLists.txt b/src/quickcontrols/fluentwinui3/impl/CMakeLists.txt
new file mode 100644
index 0000000000..86657afd34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/impl/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## qtquickcontrols2fluentwinui3styleimplplugin Plugin:
+#####################################################################
+
+qt_internal_add_qml_module(QuickControls2FluentWinUI3StyleImpl
+ URI "QtQuick.Controls.FluentWinUI3.impl"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ CLASS_NAME QtQuickControls2FluentWinUI3StyleImplPlugin
+ DEPENDENCIES
+ QtQuick/auto
+ PLUGIN_TARGET qtquickcontrols2fluentwinui3styleimplplugin
+ SOURCES
+ qquickfluentwinui3focusstroke_p.h qquickfluentwinui3focusstroke.cpp
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::Qml
+ Qt::QmlPrivate
+ Qt::Quick
+ Qt::QuickPrivate
+)
diff --git a/src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke.cpp b/src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke.cpp
new file mode 100644
index 0000000000..508d614f1c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke.cpp
@@ -0,0 +1,52 @@
+
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qquickfluentwinui3focusstroke_p.h"
+#include <QtGui/qpainter.h>
+#include <QtGui/qpainterpath.h>
+#include <QtQuick/private/qquickitem_p.h>
+QT_BEGIN_NAMESPACE
+QQuickFluentWinUI3FocusStroke::QQuickFluentWinUI3FocusStroke(QQuickItem *parent)
+ : QQuickPaintedItem(parent)
+{
+}
+void QQuickFluentWinUI3FocusStroke::paint(QPainter *painter)
+{
+ painter->setRenderHint(QPainter::Antialiasing);
+ QPainterPath path;
+ QRectF rect = boundingRect();
+ path.moveTo(rect.left(), rect.top() + m_radius);
+ path.lineTo(rect.left(), rect.bottom() - m_radius);
+ path.arcTo(QRectF(rect.left(), rect.bottom() - 2 * m_radius, 2 * m_radius, 2 * m_radius), 180, 90);
+ path.lineTo(rect.right() - m_radius, rect.bottom());
+ path.arcTo(QRectF(rect.right() - 2 * m_radius, rect.bottom() - 2 * m_radius, 2 * m_radius, 2 * m_radius), 270, 90);
+ path.lineTo(rect.right(), rect.top() + m_radius);
+ path.lineTo(rect.right(), rect.top() + m_radius);
+ path.lineTo(rect.right(), rect.top());
+ path.lineTo(rect.left(), rect.top());
+ painter->fillPath(path, m_color);
+}
+QColor QQuickFluentWinUI3FocusStroke::color() const
+{
+ return m_color;
+}
+void QQuickFluentWinUI3FocusStroke::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+ m_color = color;
+ update();
+}
+int QQuickFluentWinUI3FocusStroke::radius() const
+{
+ return m_radius;
+}
+void QQuickFluentWinUI3FocusStroke::setRadius(int radius)
+{
+ if (m_radius == radius)
+ return;
+ m_radius = radius;
+ update();
+}
+QT_END_NAMESPACE
+#include "moc_qquickfluentwinui3focusstroke_p.cpp"
diff --git a/src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke_p.h b/src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke_p.h
new file mode 100644
index 0000000000..1cf9dd1cf6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/impl/qquickfluentwinui3focusstroke_p.h
@@ -0,0 +1,39 @@
+
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QQUICKFLUENTWINUI3FOCUSSTROKE_P_H
+#define QQUICKFLUENTWINUI3FOCUSSTROKE_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 <QtGui/qcolor.h>
+#include <QtQuick/qquickpainteditem.h>
+#include <QtCore/private/qglobal_p.h>
+QT_BEGIN_NAMESPACE
+class QQuickFluentWinUI3FocusStroke : public QQuickPaintedItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
+ Q_PROPERTY(int radius READ radius WRITE setRadius FINAL)
+ QML_NAMED_ELEMENT(FocusStroke)
+ QML_ADDED_IN_VERSION(6, 8)
+public:
+ explicit QQuickFluentWinUI3FocusStroke(QQuickItem *parent = nullptr);
+ int radius() const;
+ void setRadius(int radius);
+ QColor color() const;
+ void setColor(const QColor &color);
+ void paint(QPainter *painter) override;
+private:
+ QColor m_color = Qt::white;
+ int m_radius;
+};
+QT_END_NAMESPACE
+#endif // QQUICKFLUENTWINUI3FOCUSSTROKE_P_H
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled.png
new file mode 100644
index 0000000000..f3a426b076
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..89b36fbeda
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..9e8182be8c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered.png
new file mode 100644
index 0000000000..a32df10e1e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..1aec9226ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..8be48f4ec7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed.png
new file mode 100644
index 0000000000..37c490951b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..e464cc041b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..446aaad0f2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked.png
new file mode 100644
index 0000000000..96a1da749a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked@2x.png
new file mode 100644
index 0000000000..49751722ee
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-checked@3x.png
new file mode 100644
index 0000000000..3c6fb5f985
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/button-background-disabled.png
new file mode 100644
index 0000000000..1e75999e2c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-disabled@2x.png
new file mode 100644
index 0000000000..a175375d22
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-disabled@3x.png
new file mode 100644
index 0000000000..7a4a41421e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/button-background-hovered.png
new file mode 100644
index 0000000000..ed9b9680c3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-hovered@2x.png
new file mode 100644
index 0000000000..6b0a119336
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-hovered@3x.png
new file mode 100644
index 0000000000..3f998d969b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-pressed.png b/src/quickcontrols/fluentwinui3/light/images/button-background-pressed.png
new file mode 100644
index 0000000000..1e75999e2c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-pressed@2x.png
new file mode 100644
index 0000000000..a175375d22
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background-pressed@3x.png
new file mode 100644
index 0000000000..7a4a41421e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background.png b/src/quickcontrols/fluentwinui3/light/images/button-background.png
new file mode 100644
index 0000000000..1fc4253445
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/button-background@2x.png
new file mode 100644
index 0000000000..f0e4e2a8d5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/button-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/button-background@3x.png
new file mode 100644
index 0000000000..0c3ac28643
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/button-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled.png
new file mode 100644
index 0000000000..63da5de7e5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@2x.png
new file mode 100644
index 0000000000..dfdf16a040
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@3x.png
new file mode 100644
index 0000000000..47cf90c6b2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered.png
new file mode 100644
index 0000000000..eeac692066
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..99f490bc54
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..ac6c762eab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed.png
new file mode 100644
index 0000000000..ae32aa03db
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..e8d64393a1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..d45e246e5b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked.png
new file mode 100644
index 0000000000..457ce21b50
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@2x.png
new file mode 100644
index 0000000000..307d4e1ee7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@3x.png
new file mode 100644
index 0000000000..48d12e1bfa
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked.png
new file mode 100644
index 0000000000..bf72626431
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@2x.png
new file mode 100644
index 0000000000..e98f17b49b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@3x.png
new file mode 100644
index 0000000000..3af1bc8a33
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled-partiallyChecked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled.png
new file mode 100644
index 0000000000..99fd3b7b27
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@2x.png
new file mode 100644
index 0000000000..f7bc658b9a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@3x.png
new file mode 100644
index 0000000000..9f2615c189
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked.png
new file mode 100644
index 0000000000..a97fee4277
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@2x.png
new file mode 100644
index 0000000000..5088770c20
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@3x.png
new file mode 100644
index 0000000000..b46bba9417
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered-partiallyChecked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered.png
new file mode 100644
index 0000000000..02b068f420
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@2x.png
new file mode 100644
index 0000000000..5ea65d1ebe
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@3x.png
new file mode 100644
index 0000000000..9f51751e12
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed.png
new file mode 100644
index 0000000000..1eb04dc67a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@2x.png
new file mode 100644
index 0000000000..d311e7017a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@3x.png
new file mode 100644
index 0000000000..ce90106703
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked.png
new file mode 100644
index 0000000000..75af72bee0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@2x.png
new file mode 100644
index 0000000000..906cc9c372
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@3x.png
new file mode 100644
index 0000000000..de61118a43
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-partiallyChecked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed.png
new file mode 100644
index 0000000000..d46364bd28
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@2x.png
new file mode 100644
index 0000000000..1fc0fe737d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@3x.png
new file mode 100644
index 0000000000..0a06819118
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator.png
new file mode 100644
index 0000000000..7aeaadc5bd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@2x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@2x.png
new file mode 100644
index 0000000000..3bb4cc26eb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@3x.png b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@3x.png
new file mode 100644
index 0000000000..801c430a38
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/checkbox-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-disabled.png
new file mode 100644
index 0000000000..94b89d13e9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-disabled@2x.png
new file mode 100644
index 0000000000..6ea1717f2f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-disabled@3x.png
new file mode 100644
index 0000000000..4b8c839c11
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-focused.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-focused.png
new file mode 100644
index 0000000000..02ca983090
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-focused.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-focused@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-focused@2x.png
new file mode 100644
index 0000000000..f08de8b427
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-focused@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-focused@3x.png
new file mode 100644
index 0000000000..7584fecf9d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered-open.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered-open.png
new file mode 100644
index 0000000000..ef6e1eec2d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered-open@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered-open@2x.png
new file mode 100644
index 0000000000..c823e20184
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered-open@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered-open@3x.png
new file mode 100644
index 0000000000..fd3cb119ca
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered.png
new file mode 100644
index 0000000000..ef6e1eec2d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered@2x.png
new file mode 100644
index 0000000000..c823e20184
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered@3x.png
new file mode 100644
index 0000000000..fd3cb119ca
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-open-pressed.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-open-pressed.png
new file mode 100644
index 0000000000..94b89d13e9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-open-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-open-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-open-pressed@2x.png
new file mode 100644
index 0000000000..6ea1717f2f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-open-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-open-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-open-pressed@3x.png
new file mode 100644
index 0000000000..4b8c839c11
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-open-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-open.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-open.png
new file mode 100644
index 0000000000..02ca983090
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-open@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-open@2x.png
new file mode 100644
index 0000000000..f08de8b427
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-open@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-open@3x.png
new file mode 100644
index 0000000000..7584fecf9d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-pressed.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-pressed.png
new file mode 100644
index 0000000000..94b89d13e9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-pressed@2x.png
new file mode 100644
index 0000000000..6ea1717f2f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background-pressed@3x.png
new file mode 100644
index 0000000000..4b8c839c11
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background.png
new file mode 100644
index 0000000000..02ca983090
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background@2x.png
new file mode 100644
index 0000000000..f08de8b427
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-background@3x.png
new file mode 100644
index 0000000000..7584fecf9d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-disabled.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-disabled.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-disabled@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-disabled@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-focused.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-focused.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-focused.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-focused@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-focused@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-focused@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-focused@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered-open.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered-open.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered-open@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered-open@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered-open@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered-open@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open-pressed.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open-pressed.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open-pressed@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open-pressed@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-pressed.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-pressed.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-pressed@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-pressed@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator@2x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/combobox-indicator@3x.png b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/combobox-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-hovered-open.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-hovered-open.png
new file mode 100644
index 0000000000..d1fa9fe6df
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-hovered-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-hovered-open@2x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-hovered-open@2x.png
new file mode 100644
index 0000000000..fdba8c4b53
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-hovered-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-hovered-open@3x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-hovered-open@3x.png
new file mode 100644
index 0000000000..ee907f7a2e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-hovered-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open-pressed.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open-pressed.png
new file mode 100644
index 0000000000..d1fa9fe6df
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open-pressed@2x.png
new file mode 100644
index 0000000000..fdba8c4b53
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open-pressed@3x.png
new file mode 100644
index 0000000000..ee907f7a2e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open.png
new file mode 100644
index 0000000000..d1fa9fe6df
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open@2x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open@2x.png
new file mode 100644
index 0000000000..fdba8c4b53
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open@3x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open@3x.png
new file mode 100644
index 0000000000..ee907f7a2e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-background-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-hovered-open.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-hovered-open.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-hovered-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-hovered-open@2x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-hovered-open@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-hovered-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-hovered-open@3x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-hovered-open@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-hovered-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open-pressed.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open-pressed.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open-pressed@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open-pressed@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open.png
new file mode 100644
index 0000000000..17982b7905
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open@2x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open@2x.png
new file mode 100644
index 0000000000..5a908784d1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open@3x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open@3x.png
new file mode 100644
index 0000000000..e20d493175
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-indicator-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-hovered-open.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-hovered-open.png
new file mode 100644
index 0000000000..8d8c7f28ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-hovered-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-hovered-open@2x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-hovered-open@2x.png
new file mode 100644
index 0000000000..4ff2b328b9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-hovered-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-hovered-open@3x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-hovered-open@3x.png
new file mode 100644
index 0000000000..9869023a49
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-hovered-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open-pressed.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open-pressed.png
new file mode 100644
index 0000000000..8d8c7f28ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open-pressed@2x.png
new file mode 100644
index 0000000000..4ff2b328b9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open-pressed@3x.png
new file mode 100644
index 0000000000..9869023a49
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open.png
new file mode 100644
index 0000000000..8d8c7f28ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open@2x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open@2x.png
new file mode 100644
index 0000000000..4ff2b328b9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open@3x.png b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open@3x.png
new file mode 100644
index 0000000000..9869023a49
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/editablecombobox-popup-background-open@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled.png
new file mode 100644
index 0000000000..e999fcd9cf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..14e8650f7a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..f6860a32ea
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered.png
new file mode 100644
index 0000000000..983e266871
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..c071b8ae5c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..afaeb91c24
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed.png
new file mode 100644
index 0000000000..89370c587f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..874f2a3171
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..0672407c2f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked.png
new file mode 100644
index 0000000000..63eb721583
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@2x.png
new file mode 100644
index 0000000000..391ca67c9b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@3x.png
new file mode 100644
index 0000000000..59ca1351ce
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled.png
new file mode 100644
index 0000000000..d38a2945ec
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@2x.png
new file mode 100644
index 0000000000..68574ca6c5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@3x.png
new file mode 100644
index 0000000000..54833f0a79
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered.png
new file mode 100644
index 0000000000..70cf12d0f8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@2x.png
new file mode 100644
index 0000000000..ca805865a8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@3x.png
new file mode 100644
index 0000000000..b1a48e6d92
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed.png
new file mode 100644
index 0000000000..04bee7df8f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@2x.png
new file mode 100644
index 0000000000..4c7b771916
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@3x.png
new file mode 100644
index 0000000000..654ca2917f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/flatbutton-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/frame-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/frame-background-disabled.png
new file mode 100644
index 0000000000..950b552964
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/frame-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/frame-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/frame-background-disabled@2x.png
new file mode 100644
index 0000000000..c0ad4fbb34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/frame-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/frame-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/frame-background-disabled@3x.png
new file mode 100644
index 0000000000..0adccfadbf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/frame-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/frame-background.png b/src/quickcontrols/fluentwinui3/light/images/frame-background.png
new file mode 100644
index 0000000000..950b552964
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/frame-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/frame-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/frame-background@2x.png
new file mode 100644
index 0000000000..c0ad4fbb34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/frame-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/frame-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/frame-background@3x.png
new file mode 100644
index 0000000000..0adccfadbf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/frame-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-hovered.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-hovered.png
new file mode 100644
index 0000000000..0f61dd9b8b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-hovered@2x.png
new file mode 100644
index 0000000000..cc20bdbeb5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-hovered@3x.png
new file mode 100644
index 0000000000..aae4bf62d7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-pressed.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-pressed.png
new file mode 100644
index 0000000000..d6b022ab13
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-pressed@2x.png
new file mode 100644
index 0000000000..0d89e35b0b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-pressed@3x.png
new file mode 100644
index 0000000000..b42360e129
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted.png
new file mode 100644
index 0000000000..d6b022ab13
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted@2x.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted@2x.png
new file mode 100644
index 0000000000..0d89e35b0b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted@3x.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted@3x.png
new file mode 100644
index 0000000000..b42360e129
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-highlighted@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-hovered.png
new file mode 100644
index 0000000000..d6b022ab13
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-hovered@2x.png
new file mode 100644
index 0000000000..0d89e35b0b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-hovered@3x.png
new file mode 100644
index 0000000000..b42360e129
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-pressed.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-pressed.png
new file mode 100644
index 0000000000..0f61dd9b8b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-pressed@2x.png
new file mode 100644
index 0000000000..cc20bdbeb5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-pressed@3x.png
new file mode 100644
index 0000000000..aae4bf62d7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/itemdelegate-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/popup-background.png b/src/quickcontrols/fluentwinui3/light/images/popup-background.png
new file mode 100644
index 0000000000..cfd2c17633
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/popup-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/popup-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/popup-background@2x.png
new file mode 100644
index 0000000000..a1c2a1a815
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/popup-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/popup-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/popup-background@3x.png
new file mode 100644
index 0000000000..5bea92a6b3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/popup-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled.png
new file mode 100644
index 0000000000..e3e378345c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@2x.png
new file mode 100644
index 0000000000..dde7433852
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@3x.png
new file mode 100644
index 0000000000..7cc2351de9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove.png
new file mode 100644
index 0000000000..778a6fa1a0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove@2x.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove@2x.png
new file mode 100644
index 0000000000..bb5bb04b67
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/progressbar-groove@3x.png b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove@3x.png
new file mode 100644
index 0000000000..0c6a055c2f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/progressbar-groove@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled.png
new file mode 100644
index 0000000000..d4b4ac2f4c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@2x.png
new file mode 100644
index 0000000000..b14170af18
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@3x.png
new file mode 100644
index 0000000000..6100a1dbdc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered.png
new file mode 100644
index 0000000000..ff087aa284
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..1a84cf450f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..bb32497b9e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed.png
new file mode 100644
index 0000000000..5355792d65
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..102a5afb8d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..e9ec18d655
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked.png
new file mode 100644
index 0000000000..87def1b074
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@2x.png
new file mode 100644
index 0000000000..cb57d16648
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@3x.png
new file mode 100644
index 0000000000..240f7b765b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled.png
new file mode 100644
index 0000000000..96b9b46969
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@2x.png
new file mode 100644
index 0000000000..2d8fcae8c1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@3x.png
new file mode 100644
index 0000000000..c766b07ff5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered.png
new file mode 100644
index 0000000000..12baa9f711
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@2x.png
new file mode 100644
index 0000000000..42922541ec
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@3x.png
new file mode 100644
index 0000000000..7356706576
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed.png
new file mode 100644
index 0000000000..2cb524cb94
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@2x.png
new file mode 100644
index 0000000000..549a661fb2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@3x.png
new file mode 100644
index 0000000000..cdf54c13b0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator.png
new file mode 100644
index 0000000000..ca629420dc
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@2x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@2x.png
new file mode 100644
index 0000000000..b69426e0bf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@3x.png b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@3x.png
new file mode 100644
index 0000000000..84ea625734
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/radiobutton-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled.png
new file mode 100644
index 0000000000..327fadb2cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@2x.png
new file mode 100644
index 0000000000..a6bf59f43e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@3x.png
new file mode 100644
index 0000000000..0fe63377ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed.png
new file mode 100644
index 0000000000..327fadb2cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@2x.png
new file mode 100644
index 0000000000..a6bf59f43e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@3x.png
new file mode 100644
index 0000000000..0fe63377ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered.png
new file mode 100644
index 0000000000..00d54d428c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@2x.png
new file mode 100644
index 0000000000..a4506f8a34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@3x.png
new file mode 100644
index 0000000000..bd8713f246
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle.png
new file mode 100644
index 0000000000..00d54d428c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@2x.png
new file mode 100644
index 0000000000..a4506f8a34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@3x.png
new file mode 100644
index 0000000000..bd8713f246
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-first-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled.png
new file mode 100644
index 0000000000..3b9f471147
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@2x.png
new file mode 100644
index 0000000000..eacadf5052
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@3x.png
new file mode 100644
index 0000000000..e75e6d574c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed.png
new file mode 100644
index 0000000000..2c3d8dd49b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@2x.png
new file mode 100644
index 0000000000..664753e4e3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@3x.png
new file mode 100644
index 0000000000..72acce2411
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered.png
new file mode 100644
index 0000000000..2c3d8dd49b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@2x.png
new file mode 100644
index 0000000000..664753e4e3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@3x.png
new file mode 100644
index 0000000000..72acce2411
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove.png
new file mode 100644
index 0000000000..2c3d8dd49b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@2x.png
new file mode 100644
index 0000000000..664753e4e3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@3x.png
new file mode 100644
index 0000000000..72acce2411
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-groove@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled.png
new file mode 100644
index 0000000000..327fadb2cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@2x.png
new file mode 100644
index 0000000000..a6bf59f43e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@3x.png
new file mode 100644
index 0000000000..0fe63377ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed.png
new file mode 100644
index 0000000000..327fadb2cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@2x.png
new file mode 100644
index 0000000000..a6bf59f43e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@3x.png
new file mode 100644
index 0000000000..0fe63377ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered.png
new file mode 100644
index 0000000000..00d54d428c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@2x.png
new file mode 100644
index 0000000000..a4506f8a34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@3x.png
new file mode 100644
index 0000000000..bd8713f246
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle.png
new file mode 100644
index 0000000000..00d54d428c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@2x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@2x.png
new file mode 100644
index 0000000000..a4506f8a34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@3x.png b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@3x.png
new file mode 100644
index 0000000000..bd8713f246
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/rangeslider-second-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled.png
new file mode 100644
index 0000000000..5d3e751292
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@2x.png
new file mode 100644
index 0000000000..89fb02d418
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@3x.png
new file mode 100644
index 0000000000..425ff1a7c8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered.png
new file mode 100644
index 0000000000..4f6ac3d0b7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@2x.png
new file mode 100644
index 0000000000..4eb9b632af
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@3x.png
new file mode 100644
index 0000000000..3a048d9bbf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed.png
new file mode 100644
index 0000000000..4f6ac3d0b7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@2x.png
new file mode 100644
index 0000000000..4eb9b632af
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@3x.png
new file mode 100644
index 0000000000..3a048d9bbf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove.png
new file mode 100644
index 0000000000..4f6ac3d0b7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove@2x.png
new file mode 100644
index 0000000000..4eb9b632af
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-groove@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-groove@3x.png
new file mode 100644
index 0000000000..3a048d9bbf
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-groove@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled.png
new file mode 100644
index 0000000000..327fadb2cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@2x.png
new file mode 100644
index 0000000000..a6bf59f43e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@3x.png
new file mode 100644
index 0000000000..0fe63377ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered.png
new file mode 100644
index 0000000000..00d54d428c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@2x.png
new file mode 100644
index 0000000000..a4506f8a34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@3x.png
new file mode 100644
index 0000000000..bd8713f246
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed.png
new file mode 100644
index 0000000000..327fadb2cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@2x.png
new file mode 100644
index 0000000000..a6bf59f43e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@3x.png
new file mode 100644
index 0000000000..0fe63377ab
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle.png
new file mode 100644
index 0000000000..00d54d428c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle@2x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle@2x.png
new file mode 100644
index 0000000000..a4506f8a34
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/slider-handle@3x.png b/src/quickcontrols/fluentwinui3/light/images/slider-handle@3x.png
new file mode 100644
index 0000000000..bd8713f246
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/slider-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-atlimit.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-atlimit.png
new file mode 100644
index 0000000000..4ab6def7ad
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-atlimit.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-atlimit@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-atlimit@2x.png
new file mode 100644
index 0000000000..69ce37b6b3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-atlimit@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-atlimit@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-atlimit@3x.png
new file mode 100644
index 0000000000..d416ca7380
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-atlimit@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-disabled.png
new file mode 100644
index 0000000000..ee229de334
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-disabled@2x.png
new file mode 100644
index 0000000000..0975c73719
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-disabled@3x.png
new file mode 100644
index 0000000000..ffd926acfa
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-hovered.png
new file mode 100644
index 0000000000..4ab6def7ad
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-hovered@2x.png
new file mode 100644
index 0000000000..69ce37b6b3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-hovered@3x.png
new file mode 100644
index 0000000000..d416ca7380
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-pressed.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-pressed.png
new file mode 100644
index 0000000000..4ab6def7ad
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-pressed@2x.png
new file mode 100644
index 0000000000..69ce37b6b3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-pressed@3x.png
new file mode 100644
index 0000000000..d416ca7380
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-down-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-hovered.png
new file mode 100644
index 0000000000..c0389926b5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-hovered@2x.png
new file mode 100644
index 0000000000..78b19b4b2a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-hovered@3x.png
new file mode 100644
index 0000000000..e52d395435
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-hovered.png
new file mode 100644
index 0000000000..4ab6def7ad
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-hovered@2x.png
new file mode 100644
index 0000000000..69ce37b6b3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-hovered@3x.png
new file mode 100644
index 0000000000..d416ca7380
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-pressed.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-pressed.png
new file mode 100644
index 0000000000..4ab6def7ad
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-pressed@2x.png
new file mode 100644
index 0000000000..69ce37b6b3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-pressed@3x.png
new file mode 100644
index 0000000000..d416ca7380
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background-up-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background.png
new file mode 100644
index 0000000000..4ab6def7ad
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background@2x.png
new file mode 100644
index 0000000000..69ce37b6b3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-background@3x.png
new file mode 100644
index 0000000000..d416ca7380
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-atlimit.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-atlimit.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-atlimit.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-atlimit@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-atlimit@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-atlimit@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-atlimit@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-atlimit@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-atlimit@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-disabled.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-disabled@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-disabled@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-hovered.png
new file mode 100644
index 0000000000..0ec3f53484
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-hovered@2x.png
new file mode 100644
index 0000000000..9f7f192868
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-hovered@3x.png
new file mode 100644
index 0000000000..f6c87a5570
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-pressed.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-pressed.png
new file mode 100644
index 0000000000..0ec3f53484
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-pressed@2x.png
new file mode 100644
index 0000000000..9f7f192868
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-pressed@3x.png
new file mode 100644
index 0000000000..f6c87a5570
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-down-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-hovered.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-hovered@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-hovered@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-hovered.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-hovered@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-hovered@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-pressed.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-pressed.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-pressed@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-pressed@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background-up-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-atlimit.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-atlimit.png
new file mode 100644
index 0000000000..0a0ca3624a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-atlimit.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-atlimit@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-atlimit@2x.png
new file mode 100644
index 0000000000..f2250164d2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-atlimit@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-atlimit@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-atlimit@3x.png
new file mode 100644
index 0000000000..46779b3ef2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-atlimit@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-disabled.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-disabled.png
new file mode 100644
index 0000000000..0a0ca3624a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-disabled@2x.png
new file mode 100644
index 0000000000..f2250164d2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-disabled@3x.png
new file mode 100644
index 0000000000..46779b3ef2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-hovered.png
new file mode 100644
index 0000000000..df8c7ce1d9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-hovered@2x.png
new file mode 100644
index 0000000000..8b100a15cd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-hovered@3x.png
new file mode 100644
index 0000000000..79a5901e41
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-pressed.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-pressed.png
new file mode 100644
index 0000000000..75c66f3fef
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-pressed@2x.png
new file mode 100644
index 0000000000..4874e8f328
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-pressed@3x.png
new file mode 100644
index 0000000000..53a248fd29
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-down-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-hovered.png
new file mode 100644
index 0000000000..df8c7ce1d9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-hovered@2x.png
new file mode 100644
index 0000000000..8b100a15cd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-hovered@3x.png
new file mode 100644
index 0000000000..79a5901e41
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-hovered.png
new file mode 100644
index 0000000000..df8c7ce1d9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-hovered@2x.png
new file mode 100644
index 0000000000..8b100a15cd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-hovered@3x.png
new file mode 100644
index 0000000000..79a5901e41
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-pressed.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-pressed.png
new file mode 100644
index 0000000000..df8c7ce1d9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-pressed@2x.png
new file mode 100644
index 0000000000..8b100a15cd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-pressed@3x.png
new file mode 100644
index 0000000000..79a5901e41
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon-up-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon.png
new file mode 100644
index 0000000000..df8c7ce1d9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon@2x.png
new file mode 100644
index 0000000000..8b100a15cd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon@3x.png
new file mode 100644
index 0000000000..79a5901e41
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-down-icon@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-atlimit.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-atlimit.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-atlimit.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-atlimit@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-atlimit@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-atlimit@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-atlimit@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-atlimit@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-atlimit@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-disabled.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-disabled@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-disabled@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-hovered.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-hovered@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-hovered@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-pressed.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-pressed.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-pressed@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-pressed@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-down-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-hovered.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-hovered@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-hovered@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-hovered.png
new file mode 100644
index 0000000000..0ec3f53484
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-hovered@2x.png
new file mode 100644
index 0000000000..9f7f192868
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-hovered@3x.png
new file mode 100644
index 0000000000..f6c87a5570
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-pressed.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-pressed.png
new file mode 100644
index 0000000000..0ec3f53484
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-pressed@2x.png
new file mode 100644
index 0000000000..9f7f192868
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-pressed@3x.png
new file mode 100644
index 0000000000..f6c87a5570
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background-up-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background.png
new file mode 100644
index 0000000000..ac7fcdd9ae
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background@2x.png
new file mode 100644
index 0000000000..572d530d05
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background@3x.png
new file mode 100644
index 0000000000..ae478bd384
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-atlimit.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-atlimit.png
new file mode 100644
index 0000000000..fe7388bb77
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-atlimit.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-atlimit@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-atlimit@2x.png
new file mode 100644
index 0000000000..2f9e96fffb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-atlimit@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-atlimit@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-atlimit@3x.png
new file mode 100644
index 0000000000..102e2149a0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-atlimit@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-disabled.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-disabled.png
new file mode 100644
index 0000000000..fe7388bb77
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-disabled@2x.png
new file mode 100644
index 0000000000..2f9e96fffb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-disabled@3x.png
new file mode 100644
index 0000000000..102e2149a0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-hovered.png
new file mode 100644
index 0000000000..8dc32cc618
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-hovered@2x.png
new file mode 100644
index 0000000000..004d31717c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-hovered@3x.png
new file mode 100644
index 0000000000..3e514880f2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-pressed.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-pressed.png
new file mode 100644
index 0000000000..8dc32cc618
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-pressed@2x.png
new file mode 100644
index 0000000000..004d31717c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-pressed@3x.png
new file mode 100644
index 0000000000..3e514880f2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-down-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-hovered.png
new file mode 100644
index 0000000000..8dc32cc618
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-hovered@2x.png
new file mode 100644
index 0000000000..004d31717c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-hovered@3x.png
new file mode 100644
index 0000000000..3e514880f2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-hovered.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-hovered.png
new file mode 100644
index 0000000000..8dc32cc618
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-hovered@2x.png
new file mode 100644
index 0000000000..004d31717c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-hovered@3x.png
new file mode 100644
index 0000000000..3e514880f2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-pressed.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-pressed.png
new file mode 100644
index 0000000000..6c19a90e8b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-pressed@2x.png
new file mode 100644
index 0000000000..1d894ca5aa
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-pressed@3x.png
new file mode 100644
index 0000000000..3f810b6c1a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon-up-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon.png
new file mode 100644
index 0000000000..8dc32cc618
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon@2x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon@2x.png
new file mode 100644
index 0000000000..004d31717c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon@3x.png b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon@3x.png
new file mode 100644
index 0000000000..3e514880f2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/spinbox-indicator-up-icon@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled.png
new file mode 100644
index 0000000000..e0fff15e93
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..e1be62c482
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..2e7459ec21
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered.png
new file mode 100644
index 0000000000..7809055f68
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..18a5afb7b5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..c09fcb3a06
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed.png
new file mode 100644
index 0000000000..d917aab394
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..ffeeaa73d6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..d1012d151c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked.png
new file mode 100644
index 0000000000..920bae7814
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@2x.png
new file mode 100644
index 0000000000..71b02bf596
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@3x.png
new file mode 100644
index 0000000000..a2a86d0c09
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled.png
new file mode 100644
index 0000000000..67bcb723d3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@2x.png
new file mode 100644
index 0000000000..659e00542e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@3x.png
new file mode 100644
index 0000000000..8f7aa12f03
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered.png
new file mode 100644
index 0000000000..c31f0583b6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@2x.png
new file mode 100644
index 0000000000..7f916c1d63
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@3x.png
new file mode 100644
index 0000000000..2b0503fb10
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed.png
new file mode 100644
index 0000000000..3f82932c93
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@2x.png
new file mode 100644
index 0000000000..be4317c0d9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@3x.png
new file mode 100644
index 0000000000..89c76fd903
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background.png
new file mode 100644
index 0000000000..aa5841ef12
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background@2x.png
new file mode 100644
index 0000000000..6802916ceb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background@3x.png
new file mode 100644
index 0000000000..9d3c9ed597
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled.png
new file mode 100644
index 0000000000..507678fb0a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@2x.png
new file mode 100644
index 0000000000..53a97e82f1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@3x.png
new file mode 100644
index 0000000000..2664482c67
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered.png
new file mode 100644
index 0000000000..16dce3eb3a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@2x.png
new file mode 100644
index 0000000000..2b91d9655c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@3x.png
new file mode 100644
index 0000000000..81c046d9cb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed.png
new file mode 100644
index 0000000000..5560d91461
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@2x.png
new file mode 100644
index 0000000000..9e4976b90a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@3x.png
new file mode 100644
index 0000000000..387072edf7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked.png
new file mode 100644
index 0000000000..507678fb0a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@2x.png
new file mode 100644
index 0000000000..53a97e82f1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@3x.png
new file mode 100644
index 0000000000..2664482c67
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled.png
new file mode 100644
index 0000000000..334e1d3be6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@2x.png
new file mode 100644
index 0000000000..09ff252d95
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@3x.png
new file mode 100644
index 0000000000..589758481e
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered.png
new file mode 100644
index 0000000000..fdb1eb75b8
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@2x.png
new file mode 100644
index 0000000000..0271df3682
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@3x.png
new file mode 100644
index 0000000000..f6ab9463a4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed.png
new file mode 100644
index 0000000000..cac0bfc05b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@2x.png
new file mode 100644
index 0000000000..1aaa14a005
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@3x.png
new file mode 100644
index 0000000000..021ae5309b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle.png
new file mode 100644
index 0000000000..c4c16ed8e5
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle@2x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle@2x.png
new file mode 100644
index 0000000000..252db9cecd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/switch-handle@3x.png b/src/quickcontrols/fluentwinui3/light/images/switch-handle@3x.png
new file mode 100644
index 0000000000..1ebf2fbd5c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/switch-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled.png
new file mode 100644
index 0000000000..87aa3df215
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@2x.png
new file mode 100644
index 0000000000..ba01f09f71
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@3x.png
new file mode 100644
index 0000000000..efcc5d70ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused.png
new file mode 100644
index 0000000000..a83a495d72
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@2x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@2x.png
new file mode 100644
index 0000000000..66547620a9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@3x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@3x.png
new file mode 100644
index 0000000000..fb7967a0d9
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered.png
new file mode 100644
index 0000000000..87aa3df215
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@2x.png
new file mode 100644
index 0000000000..ba01f09f71
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@3x.png
new file mode 100644
index 0000000000..efcc5d70ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background.png
new file mode 100644
index 0000000000..87aa3df215
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background@2x.png
new file mode 100644
index 0000000000..ba01f09f71
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textarea-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/textarea-background@3x.png
new file mode 100644
index 0000000000..efcc5d70ac
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textarea-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled.png
new file mode 100644
index 0000000000..b6011c6f32
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@2x.png
new file mode 100644
index 0000000000..e356a2f6e6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@3x.png
new file mode 100644
index 0000000000..d61430ece2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused.png
new file mode 100644
index 0000000000..a8a36e097f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@2x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@2x.png
new file mode 100644
index 0000000000..4bf8fb51aa
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@3x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@3x.png
new file mode 100644
index 0000000000..b5086ccfb4
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered.png
new file mode 100644
index 0000000000..f2534b323c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@2x.png
new file mode 100644
index 0000000000..114c319f83
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@3x.png
new file mode 100644
index 0000000000..2a5ca99d46
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background.png
new file mode 100644
index 0000000000..dd1edf825a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background@2x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background@2x.png
new file mode 100644
index 0000000000..6615914a97
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/textfield-background@3x.png b/src/quickcontrols/fluentwinui3/light/images/textfield-background@3x.png
new file mode 100644
index 0000000000..7c5983a8b2
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/textfield-background@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-disabled.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-disabled.png
new file mode 100644
index 0000000000..b6054fbd90
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-disabled@2x.png
new file mode 100644
index 0000000000..aca559422a
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-disabled@3x.png
new file mode 100644
index 0000000000..b7b68b4ef7
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-hovered.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-hovered.png
new file mode 100644
index 0000000000..08f56b2c8f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..94acc63e7f
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..f2985b2d3b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-pressed.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-pressed.png
new file mode 100644
index 0000000000..bfeea7584b
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-pressed@2x.png
new file mode 100644
index 0000000000..434dbbc450
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-pressed@3x.png
new file mode 100644
index 0000000000..a417dfb5fd
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked.png
new file mode 100644
index 0000000000..9f1512fd12
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked@2x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked@2x.png
new file mode 100644
index 0000000000..8368e02601
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked@3x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked@3x.png
new file mode 100644
index 0000000000..11f120e83d
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-disabled.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-disabled.png
new file mode 100644
index 0000000000..9d292c4415
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-disabled@2x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-disabled@2x.png
new file mode 100644
index 0000000000..32af78bc8c
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-disabled@3x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-disabled@3x.png
new file mode 100644
index 0000000000..a543a36720
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-hovered.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-hovered.png
new file mode 100644
index 0000000000..6f3fec4a36
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-hovered@2x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-hovered@2x.png
new file mode 100644
index 0000000000..3fb9cceceb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-hovered@3x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-hovered@3x.png
new file mode 100644
index 0000000000..6fe3bc2bcb
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-pressed.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-pressed.png
new file mode 100644
index 0000000000..99aa8a6de1
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-pressed@2x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-pressed@2x.png
new file mode 100644
index 0000000000..a6bc176cb6
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-pressed@3x.png b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-pressed@3x.png
new file mode 100644
index 0000000000..06bc0c64b0
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/light/images/toolbutton-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme.cpp b/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme.cpp
new file mode 100644
index 0000000000..93d96dc842
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme.cpp
@@ -0,0 +1,142 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquickfluentwinui3theme_p.h"
+
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qstylehints.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qfontdatabase.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// If on a Windows11 or above, the platform theme will be used to populate the palette
+// We need to fallback to hardcoded colors when using the style on other platforms,
+// that's why we need the following
+// The colors for Windows 11 are taken from the official WinUI3 Figma style at
+// https://www.figma.com/community/file/1159947337437047524
+// Try to keep these consistent with the widget windows11 style
+enum WinUI3Color {
+ solidBackground, // Solid background color used for the bottom most layer
+ textPrimary, // Color for UI labels and static text
+ textSecondary, // Color for text in pressed controls
+ textDisabled, // Color for disabled text
+ textOnAccentPrimary, // Color of text on controls filled in accent color
+ textOnAccentSecondary, // Color of text on sunken controls in accent color
+ textOnAccentDisabled, // Color of text on disabled controls in accent color
+ controlDefault, // Color for standard controls
+ controlDisabled, // Color for disabled controls
+ controlStrokeDefault, // Color for gradient stops in elevations (pressed or disabled state)
+ controlStrokeSecondary, // Color for gradient stops in elevations
+ accentDefault, // Default color for accent fills on controls
+ accentDisabled, // Default color for accent fills on disabled controls
+ accentSecondary, // Color for accent fills on hovered controls
+};
+
+const static QColor WINUI3ColorsLight [] {
+ QColor(0xF3,0xF3,0xF3,0xFF), //solidBackgroundColor
+ QColor(0x00,0x00,0x00,0xE4), //textPrimary
+ QColor(0x00,0x00,0x00,0x9E), //textSecondary
+ QColor(0x00,0x00,0x00,0x5C), //textDisabled
+ QColor(0xFF,0xFF,0xFF,0xFF), //textOnAccentPrimary
+ QColor(0xFF,0xFF,0xFF,0x7F), //textOnAccentSecondary
+ QColor(0xFF,0xFF,0xFF,0xFF), //textOnAccentDisabled
+ QColor(0xFF,0xFF,0xFF,0xB3), //controlDefault
+ QColor(0xF9,0xF9,0xF9,0x4D), //controlDisabled
+ QColor(0x00,0x00,0x00,0x0F), //controlStrokeDefault
+ QColor(0x00,0x00,0x00,0x29), //controlStrokeSecondary
+ QColor(0x00,0x5F,0xB8,0xFF), //accentDefault
+ QColor(0x00,0x00,0x00,0x37), //accentDisabled
+ QColor(0x00,0x5F,0xB8,0xE6), //accentSecondary
+};
+
+const static QColor WINUI3ColorsDark[] {
+ QColor(0x20,0x20,0x20,0xFF), //solidBackgroundColor
+ QColor(0xFF,0xFF,0xFF,0xFF), //textPrimary
+ QColor(0xFF,0xFF,0xFF,0xC5), //textSecondary
+ QColor(0xFF,0xFF,0xFF,0x5D), //textDisabled
+ QColor(0x00,0x00,0x00,0xFF), //textOnAccentPrimary
+ QColor(0x00,0x00,0x00,0x80), //textOnAccentSecondary
+ QColor(0xFF,0xFF,0xFF,0x87), //textOnAccentDisabled
+ QColor(0xFF,0xFF,0xFF,0x0F), //controlDefault
+ QColor(0xFF,0xFF,0xFF,0x11), //controlDisabled
+ QColor(0xFF,0xFF,0xFF,0x12), //controlStrokeDefault
+ QColor(0xFF,0xFF,0xFF,0x18), //controlStrokeSecondary
+ QColor(0x60,0xCD,0xFF,0xFF), //accentDefault
+ QColor(0xFF,0xFF,0xFF,0x28), //accentDisabled
+ QColor(0x60,0xCD,0xFF,0xE6) // accentSecondary
+};
+
+const static QColor* WINUI3Colors[] {
+ WINUI3ColorsLight,
+ WINUI3ColorsDark
+};
+
+static void populateSystemPalette(QPalette &palette)
+{
+ const auto colorSchemeIndex = QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Light ? 0 : 1;
+
+ palette.setColor(QPalette::All, QPalette::Window, WINUI3Colors[colorSchemeIndex][solidBackground]);
+
+ palette.setColor(QPalette::All, QPalette::WindowText, WINUI3Colors[colorSchemeIndex][textPrimary]);
+ palette.setColor(QPalette::Disabled, QPalette::WindowText, WINUI3Colors[colorSchemeIndex][textDisabled]);
+
+ palette.setColor(QPalette::All, QPalette::Text, WINUI3Colors[colorSchemeIndex][textPrimary]);
+ palette.setColor(QPalette::Disabled, QPalette::Text, WINUI3Colors[colorSchemeIndex][textDisabled]);
+
+ palette.setColor(QPalette::All, QPalette::PlaceholderText, WINUI3Colors[colorSchemeIndex][textSecondary]);
+ palette.setColor(QPalette::Disabled, QPalette::PlaceholderText, WINUI3Colors[colorSchemeIndex][textDisabled]);
+
+ palette.setColor(QPalette::All, QPalette::Button, WINUI3Colors[colorSchemeIndex][controlDefault]);
+ palette.setColor(QPalette::Disabled, QPalette::Button, WINUI3Colors[colorSchemeIndex][controlDisabled]);
+ palette.setColor(QPalette::All, QPalette::ButtonText, WINUI3Colors[colorSchemeIndex][textPrimary]);
+ palette.setColor(QPalette::Disabled, QPalette::ButtonText, WINUI3Colors[colorSchemeIndex][textDisabled]);
+ palette.setColor(QPalette::All, QPalette::BrightText, WINUI3Colors[colorSchemeIndex][textSecondary]);
+
+ palette.setColor(QPalette::All, QPalette::Highlight, WINUI3Colors[colorSchemeIndex][accentDefault]);
+ palette.setColor(QPalette::Disabled, QPalette::Highlight, WINUI3Colors[colorSchemeIndex][accentDisabled]);
+ palette.setColor(QPalette::All, QPalette::Accent, WINUI3Colors[colorSchemeIndex][accentDefault]);
+ palette.setColor(QPalette::Disabled, QPalette::Accent, WINUI3Colors[colorSchemeIndex][accentDisabled]);
+
+ palette.setColor(QPalette::All, QPalette::HighlightedText, WINUI3Colors[colorSchemeIndex][textOnAccentPrimary]);
+ palette.setColor(QPalette::Disabled, QPalette::HighlightedText, WINUI3Colors[colorSchemeIndex][textOnAccentDisabled]);
+}
+
+static void populateThemeFont(QQuickTheme *theme)
+{
+ QFont systemFont;
+ QFont toolBarFont;
+
+ const QLatin1String segoeUiFamilyName("Segoe UI Variable");
+ if (QFontDatabase::families().contains(segoeUiFamilyName)) {
+ const QFont segoeFont(segoeUiFamilyName);
+ const QStringList families{segoeFont.family()};
+ systemFont.setFamilies(families);
+ toolBarFont.setFamilies(families);
+ }
+ systemFont.setWeight(QFont::Weight::Normal);
+ toolBarFont.setWeight(QFont::Weight::Normal);
+
+ systemFont.setPixelSize(14);
+ toolBarFont.setPixelSize(12);
+
+ theme->setFont(QQuickTheme::System, systemFont);
+ theme->setFont(QQuickTheme::ToolBar, toolBarFont);
+}
+
+void QQuickFluentWinUI3Theme::updatePalette(QPalette &palette)
+{
+ populateSystemPalette(palette);
+}
+
+void QQuickFluentWinUI3Theme::initialize(QQuickTheme *theme)
+{
+ populateThemeFont(theme);
+
+ QPalette systemPalette;
+ updatePalette(systemPalette);
+ theme->setPalette(QQuickTheme::System, systemPalette);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme_p.h b/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme_p.h
new file mode 100644
index 0000000000..bf098cec82
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/qquickfluentwinui3theme_p.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQUICKFLUENTWINUI3THEME_P_H
+#define QQUICKFLUENTWINUI3THEME_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 <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTheme;
+class QPalette;
+class QQuickFluentWinUI3Theme
+{
+public:
+ static void initialize(QQuickTheme *theme);
+ static void updatePalette(QPalette &palette);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFLUENTWINUI3THEME_P_H
diff --git a/src/quickcontrols/fluentwinui3/qtquickcontrols2fluentwinui3styleplugin.cpp b/src/quickcontrols/fluentwinui3/qtquickcontrols2fluentwinui3styleplugin.cpp
new file mode 100644
index 0000000000..6baf774dd3
--- /dev/null
+++ b/src/quickcontrols/fluentwinui3/qtquickcontrols2fluentwinui3styleplugin.cpp
@@ -0,0 +1,56 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquickfluentwinui3theme_p.h"
+
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+QT_BEGIN_NAMESPACE
+
+extern void qml_register_types_QtQuick_Controls_FluentWinUI3();
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_Controls_FluentWinUI3);
+
+class QtQuickControls2FluentWinUI3StylePlugin : public QQuickStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickControls2FluentWinUI3StylePlugin(QObject *parent = nullptr);
+
+ QString name() const override;
+ void initializeTheme(QQuickTheme *theme) override;
+ void updateTheme() override;
+
+ QQuickFluentWinUI3Theme theme;
+};
+
+QtQuickControls2FluentWinUI3StylePlugin::QtQuickControls2FluentWinUI3StylePlugin(QObject *parent) : QQuickStylePlugin(parent)
+{
+ volatile auto registration = &qml_register_types_QtQuick_Controls_FluentWinUI3;
+ Q_UNUSED(registration);
+}
+
+QString QtQuickControls2FluentWinUI3StylePlugin::name() const
+{
+ return QStringLiteral("FluentWinUI3");
+}
+
+void QtQuickControls2FluentWinUI3StylePlugin::initializeTheme(QQuickTheme *theme)
+{
+ this->theme.initialize(theme);
+}
+
+void QtQuickControls2FluentWinUI3StylePlugin::updateTheme()
+{
+ QQuickTheme *theme = QQuickTheme::instance();
+ QPalette palette;
+ this->theme.updatePalette(palette);
+ theme->setPalette(QQuickTheme::System, palette);
+}
+
+QT_END_NAMESPACE
+
+#include "qtquickcontrols2fluentwinui3styleplugin.moc"
diff --git a/src/quickcontrols/fusion/CMakeLists.txt b/src/quickcontrols/fusion/CMakeLists.txt
index 572a3cf931..0c751db621 100644
--- a/src/quickcontrols/fusion/CMakeLists.txt
+++ b/src/quickcontrols/fusion/CMakeLists.txt
@@ -122,7 +122,6 @@ qt_internal_add_qml_module(QuickControls2Fusion
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
- GENERATE_CPP_EXPORTS
)
target_sources(qtquickcontrols2fusionstyleplugin
diff --git a/src/quickcontrols/fusion/CheckBox.qml b/src/quickcontrols/fusion/CheckBox.qml
index 414414804d..a996b67afe 100644
--- a/src/quickcontrols/fusion/CheckBox.qml
+++ b/src/quickcontrols/fusion/CheckBox.qml
@@ -22,6 +22,7 @@ T.CheckBox {
indicator: CheckIndicator {
x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
y: control.topPadding + (control.availableHeight - height) / 2
+ baseLightness: control.enabled ? 1.25 : 1.0
control: control
}
diff --git a/src/quickcontrols/fusion/ComboBox.qml b/src/quickcontrols/fusion/ComboBox.qml
index 55d91e65ed..decc43f1f7 100644
--- a/src/quickcontrols/fusion/ComboBox.qml
+++ b/src/quickcontrols/fusion/ComboBox.qml
@@ -130,15 +130,15 @@ T.ComboBox {
}
background: Rectangle {
- color: palette.window
- border.color: Fusion.outline(palette)
+ color: control.popup.palette.window
+ border.color: Fusion.outline(control.palette)
Rectangle {
z: -1
x: 1; y: 1
width: parent.width
height: parent.height
- color: palette.shadow
+ color: control.palette.shadow
opacity: 0.2
}
}
diff --git a/src/quickcontrols/fusion/Dialog.qml b/src/quickcontrols/fusion/Dialog.qml
index f17321bcc0..355f079b98 100644
--- a/src/quickcontrols/fusion/Dialog.qml
+++ b/src/quickcontrols/fusion/Dialog.qml
@@ -39,7 +39,7 @@ T.Dialog {
header: Label {
text: control.title
- visible: control.title
+ visible: control.title && parent?.parent === Overlay.overlay
elide: Label.ElideRight
font.bold: true
padding: 6
diff --git a/src/quickcontrols/fusion/Tumbler.qml b/src/quickcontrols/fusion/Tumbler.qml
index 447765dce7..4a5ccd8348 100644
--- a/src/quickcontrols/fusion/Tumbler.qml
+++ b/src/quickcontrols/fusion/Tumbler.qml
@@ -15,6 +15,8 @@ T.Tumbler {
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
+ readonly property real __delegateHeight: availableHeight / visibleItemCount
+
delegate: Text {
text: modelData
color: control.palette.windowText
@@ -34,13 +36,11 @@ T.Tumbler {
delegate: control.delegate
path: Path {
startX: control.contentItem.width / 2
- startY: -control.contentItem.delegateHeight / 2
+ startY: -control.__delegateHeight / 2
PathLine {
x: control.contentItem.width / 2
- y: (control.visibleItemCount + 1) * control.contentItem.delegateHeight - control.contentItem.delegateHeight / 2
+ y: (control.visibleItemCount + 1) * control.__delegateHeight - control.__delegateHeight / 2
}
}
-
- property real delegateHeight: control.availableHeight / control.visibleItemCount
}
}
diff --git a/src/quickcontrols/fusion/impl/CheckIndicator.qml b/src/quickcontrols/fusion/impl/CheckIndicator.qml
index 58de99654a..40e3471f10 100644
--- a/src/quickcontrols/fusion/impl/CheckIndicator.qml
+++ b/src/quickcontrols/fusion/impl/CheckIndicator.qml
@@ -10,13 +10,15 @@ Rectangle {
id: indicator
property Item control
+ property real baseLightness: 1.6
+
readonly property color pressedColor: Fusion.mergedColors(control.palette.base, control.palette.windowText, 85)
readonly property color checkMarkColor: Qt.darker(control.palette.text, 1.2)
implicitWidth: 14
implicitHeight: 14
- color: control.down ? indicator.pressedColor : control.palette.base
+ color: control.down ? indicator.pressedColor : Qt.lighter(control.palette.base, baseLightness)
border.color: control.visualFocus ? Fusion.highlightedOutline(control.palette)
: Qt.lighter(Fusion.outline(control.palette), 1.1)
diff --git a/src/quickcontrols/fusion/impl/RadioIndicator.qml b/src/quickcontrols/fusion/impl/RadioIndicator.qml
index 0949b904a9..818b246953 100644
--- a/src/quickcontrols/fusion/impl/RadioIndicator.qml
+++ b/src/quickcontrols/fusion/impl/RadioIndicator.qml
@@ -17,7 +17,7 @@ Rectangle {
implicitHeight: 14
radius: width / 2
- color: control.down ? indicator.pressedColor : control.palette.base
+ color: control.down ? indicator.pressedColor : Qt.lighter(control.palette.base, 1.75)
border.color: control.visualFocus ? Fusion.highlightedOutline(control.palette)
: Qt.darker(control.palette.window, 1.5)
diff --git a/src/quickcontrols/imagine/CMakeLists.txt b/src/quickcontrols/imagine/CMakeLists.txt
index a029e09e82..5d57d51470 100644
--- a/src/quickcontrols/imagine/CMakeLists.txt
+++ b/src/quickcontrols/imagine/CMakeLists.txt
@@ -114,7 +114,6 @@ qt_internal_add_qml_module(QuickControls2Imagine
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
- GENERATE_CPP_EXPORTS
)
target_sources(qtquickcontrols2imaginestyleplugin
diff --git a/src/quickcontrols/imagine/Dialog.qml b/src/quickcontrols/imagine/Dialog.qml
index 4d3c29633e..8797d980f4 100644
--- a/src/quickcontrols/imagine/Dialog.qml
+++ b/src/quickcontrols/imagine/Dialog.qml
@@ -40,7 +40,7 @@ T.Dialog {
header: Label {
text: control.title
- visible: control.title
+ visible: parent?.parent === Overlay.overlay && control.title
elide: Label.ElideRight
font.bold: true
padding: 12
diff --git a/src/quickcontrols/imagine/Tumbler.qml b/src/quickcontrols/imagine/Tumbler.qml
index 7052c6654c..f349168ccd 100644
--- a/src/quickcontrols/imagine/Tumbler.qml
+++ b/src/quickcontrols/imagine/Tumbler.qml
@@ -20,6 +20,8 @@ T.Tumbler {
rightInset: background ? -background.rightInset || 0 : 0
bottomInset: background ? -background.bottomInset || 0 : 0
+ readonly property real __delegateHeight: availableHeight / visibleItemCount
+
delegate: Text {
text: modelData
font: control.font
@@ -39,10 +41,10 @@ T.Tumbler {
delegate: control.delegate
path: Path {
startX: control.contentItem.width / 2
- startY: -control.contentItem.delegateHeight / 2
+ startY: -control.__delegateHeight / 2
PathLine {
x: control.contentItem.width / 2
- y: (control.visibleItemCount + 1) * control.contentItem.delegateHeight - control.contentItem.delegateHeight / 2
+ y: (control.visibleItemCount + 1) * control.__delegateHeight - control.__delegateHeight / 2
}
}
diff --git a/src/quickcontrols/ios/BusyIndicator.qml b/src/quickcontrols/ios/BusyIndicator.qml
index 3fb08070df..cb0a95b861 100644
--- a/src/quickcontrols/ios/BusyIndicator.qml
+++ b/src/quickcontrols/ios/BusyIndicator.qml
@@ -27,7 +27,7 @@ T.BusyIndicator {
contentItem: Image {
property int currentImage: 8
source: IOS.url + "busyindicator-frame-0" + currentImage +
- (Qt.styleHints.colorScheme === Qt.Light ? "-light.png" : "-dark.png")
+ (Application.styleHints.colorScheme === Qt.Light ? "-light.png" : "-dark.png")
fillMode: Image.PreserveAspectFit
NumberAnimation on currentImage {
running: control.visible && control.running
diff --git a/src/quickcontrols/ios/CMakeLists.txt b/src/quickcontrols/ios/CMakeLists.txt
index c4c827677a..f3be4038a3 100644
--- a/src/quickcontrols/ios/CMakeLists.txt
+++ b/src/quickcontrols/ios/CMakeLists.txt
@@ -5,6 +5,8 @@
## qtquickcontrols2iosstyleplugin Plugin:
#####################################################################
+add_subdirectory(impl)
+
set(qml_files
"Slider.qml"
"RangeSlider.qml"
@@ -108,8 +110,6 @@ qt_internal_add_resource(qtquickcontrols2iosstyleplugin "qmake_qtquickcontrols2i
${qmake_qtquickcontrols2iosstyleplugin_resource_files}
)
-add_subdirectory(impl)
-
_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2iosstyleplugin
qtquickcontrols2iosstyleimplplugin)
diff --git a/src/quickcontrols/ios/CheckBox.qml b/src/quickcontrols/ios/CheckBox.qml
index 59f1c8bce4..13c6819e38 100644
--- a/src/quickcontrols/ios/CheckBox.qml
+++ b/src/quickcontrols/ios/CheckBox.qml
@@ -27,8 +27,8 @@ T.CheckBox {
states: [
{"checked": control.checkState === Qt.Checked},
{"partially-checked": control.checkState === Qt.PartiallyChecked},
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
diff --git a/src/quickcontrols/ios/CheckDelegate.qml b/src/quickcontrols/ios/CheckDelegate.qml
index b421430311..fd160220fb 100644
--- a/src/quickcontrols/ios/CheckDelegate.qml
+++ b/src/quickcontrols/ios/CheckDelegate.qml
@@ -32,8 +32,8 @@ T.CheckDelegate {
states: [
{"checked": control.checkState === Qt.Checked},
{"partially-checked": control.checkState === Qt.PartiallyChecked},
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
@@ -55,7 +55,7 @@ T.CheckDelegate {
background: Rectangle {
implicitHeight: 44
- color: Qt.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
+ color: Application.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
NinePatchImage {
property real offset: control.icon.source.toString() !== "" ? control.icon.width + control.spacing : 0
x: control.down ? 0 : control.leftPadding + offset
@@ -65,8 +65,8 @@ T.CheckDelegate {
source: IOS.url + "itemdelegate-background"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"pressed": control.down}
]
}
diff --git a/src/quickcontrols/ios/ComboBox.qml b/src/quickcontrols/ios/ComboBox.qml
index 7c1299db74..7ddbfbf348 100644
--- a/src/quickcontrols/ios/ComboBox.qml
+++ b/src/quickcontrols/ios/ComboBox.qml
@@ -54,8 +54,8 @@ T.ComboBox {
states: [
{"edge": isFirstItem || isLastItem },
{"single": isSingleItem},
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"pressed": down}
]
}
@@ -74,8 +74,8 @@ T.ComboBox {
: defaultColor
ImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"pressed": control.down}
]
}
diff --git a/src/quickcontrols/ios/Dial.qml b/src/quickcontrols/ios/Dial.qml
index 3fc77035b8..bac3636ab2 100644
--- a/src/quickcontrols/ios/Dial.qml
+++ b/src/quickcontrols/ios/Dial.qml
@@ -92,8 +92,8 @@ T.Dial {
source: IOS.url + "slider-handle"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"disabled": !control.enabled}
]
}
diff --git a/src/quickcontrols/ios/Dialog.qml b/src/quickcontrols/ios/Dialog.qml
index f8f400daf1..5cf877e1ad 100644
--- a/src/quickcontrols/ios/Dialog.qml
+++ b/src/quickcontrols/ios/Dialog.qml
@@ -39,8 +39,8 @@ T.Dialog {
source: IOS.url + "popup-background"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
diff --git a/src/quickcontrols/ios/DialogButtonBox.qml b/src/quickcontrols/ios/DialogButtonBox.qml
index f04088a9d1..b368a8290d 100644
--- a/src/quickcontrols/ios/DialogButtonBox.qml
+++ b/src/quickcontrols/ios/DialogButtonBox.qml
@@ -51,8 +51,8 @@ T.DialogButtonBox {
NinePatchImageSelector on source {
states: [
{"pressed": delegate.down},
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
]
}
}
@@ -67,8 +67,8 @@ T.DialogButtonBox {
source: IOS.url + "dialogbuttonbox-separator"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
diff --git a/src/quickcontrols/ios/Drawer.qml b/src/quickcontrols/ios/Drawer.qml
index 2ee955e7bc..c3a8f4cbc5 100644
--- a/src/quickcontrols/ios/Drawer.qml
+++ b/src/quickcontrols/ios/Drawer.qml
@@ -32,8 +32,8 @@ T.Drawer {
source: IOS.url + "drawer-background"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"modal": control.modal}
]
}
diff --git a/src/quickcontrols/ios/Frame.qml b/src/quickcontrols/ios/Frame.qml
index 9179366808..066017d029 100644
--- a/src/quickcontrols/ios/Frame.qml
+++ b/src/quickcontrols/ios/Frame.qml
@@ -19,6 +19,6 @@ T.Frame {
background: Rectangle {
radius: 9
- color: Qt.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
+ color: Application.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
}
}
diff --git a/src/quickcontrols/ios/GroupBox.qml b/src/quickcontrols/ios/GroupBox.qml
index d3d14e7df8..79214b9933 100644
--- a/src/quickcontrols/ios/GroupBox.qml
+++ b/src/quickcontrols/ios/GroupBox.qml
@@ -36,6 +36,6 @@ T.GroupBox {
width: parent.width
height: parent.height - control.topPadding + control.bottomPadding
radius: 9
- color: Qt.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
+ color: Application.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
}
}
diff --git a/src/quickcontrols/ios/ItemDelegate.qml b/src/quickcontrols/ios/ItemDelegate.qml
index 2b27c86b26..c2bdc1f8ce 100644
--- a/src/quickcontrols/ios/ItemDelegate.qml
+++ b/src/quickcontrols/ios/ItemDelegate.qml
@@ -36,7 +36,7 @@ T.ItemDelegate {
background: Rectangle {
implicitHeight: 44
- color: Qt.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
+ color: Application.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
NinePatchImage {
property real offset: control.icon.source.toString() !== "" ? control.icon.width + control.spacing : 0
x: control.down ? 0 : control.leftPadding + offset
@@ -46,8 +46,8 @@ T.ItemDelegate {
source: IOS.url + "itemdelegate-background"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"pressed": control.down}
]
}
diff --git a/src/quickcontrols/ios/Menu.qml b/src/quickcontrols/ios/Menu.qml
index 752737f69b..7f65f1b239 100644
--- a/src/quickcontrols/ios/Menu.qml
+++ b/src/quickcontrols/ios/Menu.qml
@@ -52,8 +52,8 @@ T.Menu {
source: IOS.url + "menu-background"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
diff --git a/src/quickcontrols/ios/MenuBar.qml b/src/quickcontrols/ios/MenuBar.qml
index b38fa12fcb..ae611667b4 100644
--- a/src/quickcontrols/ios/MenuBar.qml
+++ b/src/quickcontrols/ios/MenuBar.qml
@@ -24,7 +24,7 @@ T.MenuBar {
background: Rectangle {
opacity: 0.98
- color: Qt.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
+ color: Application.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
Rectangle {
height: 1
width: parent.width
diff --git a/src/quickcontrols/ios/MenuItem.qml b/src/quickcontrols/ios/MenuItem.qml
index 29c2562ca0..46aba80187 100644
--- a/src/quickcontrols/ios/MenuItem.qml
+++ b/src/quickcontrols/ios/MenuItem.qml
@@ -86,8 +86,8 @@ T.MenuItem {
states: [
{"edge": control.isFirstItem || control.isLastItem},
{"single": control.isSingleItem},
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"pressed": control.down}
]
}
diff --git a/src/quickcontrols/ios/MenuSeparator.qml b/src/quickcontrols/ios/MenuSeparator.qml
index 790d8f0302..b709919f79 100644
--- a/src/quickcontrols/ios/MenuSeparator.qml
+++ b/src/quickcontrols/ios/MenuSeparator.qml
@@ -18,8 +18,8 @@ T.MenuSeparator {
source: IOS.url + "menuseparator-separator"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
diff --git a/src/quickcontrols/ios/PageIndicator.qml b/src/quickcontrols/ios/PageIndicator.qml
index 9a059b5df2..ca46a8b87c 100644
--- a/src/quickcontrols/ios/PageIndicator.qml
+++ b/src/quickcontrols/ios/PageIndicator.qml
@@ -18,8 +18,8 @@ T.PageIndicator {
source: IOS.url + "pageindicator-delegate"
ImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"current": index === control.currentIndex},
]
}
diff --git a/src/quickcontrols/ios/Popup.qml b/src/quickcontrols/ios/Popup.qml
index ec76a90267..b614448997 100644
--- a/src/quickcontrols/ios/Popup.qml
+++ b/src/quickcontrols/ios/Popup.qml
@@ -35,8 +35,8 @@ T.Popup {
source: IOS.url + "popup-background"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
diff --git a/src/quickcontrols/ios/ProgressBar.qml b/src/quickcontrols/ios/ProgressBar.qml
index 20cf4dc265..36adcb0ed8 100644
--- a/src/quickcontrols/ios/ProgressBar.qml
+++ b/src/quickcontrols/ios/ProgressBar.qml
@@ -31,8 +31,8 @@ T.ProgressBar {
source: IOS.url + "slider-progress"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
@@ -46,8 +46,8 @@ T.ProgressBar {
source: IOS.url + "slider-progress"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
@@ -72,8 +72,8 @@ T.ProgressBar {
width: control.background.width
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
diff --git a/src/quickcontrols/ios/RadioButton.qml b/src/quickcontrols/ios/RadioButton.qml
index d107d9b490..d37c411e4e 100644
--- a/src/quickcontrols/ios/RadioButton.qml
+++ b/src/quickcontrols/ios/RadioButton.qml
@@ -26,8 +26,8 @@ T.RadioButton {
ImageSelector on source {
states: [
{"checked": control.checked},
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
diff --git a/src/quickcontrols/ios/RadioDelegate.qml b/src/quickcontrols/ios/RadioDelegate.qml
index 91f74b9b4f..e772a57ef4 100644
--- a/src/quickcontrols/ios/RadioDelegate.qml
+++ b/src/quickcontrols/ios/RadioDelegate.qml
@@ -32,8 +32,8 @@ T.RadioDelegate {
source: IOS.url + "radiodelegate-indicator"
ImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
@@ -55,7 +55,7 @@ T.RadioDelegate {
background: Rectangle {
implicitHeight: 44
- color: Qt.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
+ color: Application.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
NinePatchImage {
property real offset: control.icon.source.toString() !== "" ? control.icon.width + control.spacing : 0
x: control.down ? 0 : control.leftPadding + offset
@@ -65,8 +65,8 @@ T.RadioDelegate {
source: IOS.url + "itemdelegate-background"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"pressed": control.down}
]
}
diff --git a/src/quickcontrols/ios/RangeSlider.qml b/src/quickcontrols/ios/RangeSlider.qml
index aab3b0a598..e1ea15cb8b 100644
--- a/src/quickcontrols/ios/RangeSlider.qml
+++ b/src/quickcontrols/ios/RangeSlider.qml
@@ -28,8 +28,8 @@ T.RangeSlider {
source: IOS.url + "slider-handle"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
]
}
}
@@ -47,8 +47,8 @@ T.RangeSlider {
source: IOS.url + "slider-handle"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
]
}
}
@@ -67,8 +67,8 @@ T.RangeSlider {
width: control.horizontal ? control.background.width : control.background.height
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
]
}
@@ -83,8 +83,8 @@ T.RangeSlider {
source: IOS.url + "slider-progress"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
]
}
}
diff --git a/src/quickcontrols/ios/ScrollBar.qml b/src/quickcontrols/ios/ScrollBar.qml
index afd2e737b3..f8b7b1d0a6 100644
--- a/src/quickcontrols/ios/ScrollBar.qml
+++ b/src/quickcontrols/ios/ScrollBar.qml
@@ -24,8 +24,8 @@ T.ScrollBar {
source: IOS.url + "scrollindicator-handle"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"horizontal": control.horizontal},
{"vertical": control.vertical}
]
diff --git a/src/quickcontrols/ios/ScrollIndicator.qml b/src/quickcontrols/ios/ScrollIndicator.qml
index 5af880ca36..49d185b97d 100644
--- a/src/quickcontrols/ios/ScrollIndicator.qml
+++ b/src/quickcontrols/ios/ScrollIndicator.qml
@@ -18,8 +18,8 @@ T.ScrollIndicator {
source: IOS.url + "scrollindicator-handle"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"horizontal": control.horizontal},
{"vertical": control.vertical}
]
diff --git a/src/quickcontrols/ios/SelectionRectangle.qml b/src/quickcontrols/ios/SelectionRectangle.qml
index 06e540b411..99cbbe65c3 100644
--- a/src/quickcontrols/ios/SelectionRectangle.qml
+++ b/src/quickcontrols/ios/SelectionRectangle.qml
@@ -21,8 +21,8 @@ T.SelectionRectangle {
visible: SelectionRectangle.control.active
ImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
diff --git a/src/quickcontrols/ios/Slider.qml b/src/quickcontrols/ios/Slider.qml
index efa196bc72..4a392b93bc 100644
--- a/src/quickcontrols/ios/Slider.qml
+++ b/src/quickcontrols/ios/Slider.qml
@@ -26,8 +26,8 @@ T.Slider {
source: IOS.url + "slider-handle"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"disabled": !control.enabled}
]
}
@@ -47,8 +47,8 @@ T.Slider {
width: control.horizontal ? background.width : background.height
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
]
}
@@ -61,8 +61,8 @@ T.Slider {
source: IOS.url + "slider-progress"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
]
}
}
diff --git a/src/quickcontrols/ios/SpinBox.qml b/src/quickcontrols/ios/SpinBox.qml
index 4168f6b43e..38f8385eaf 100644
--- a/src/quickcontrols/ios/SpinBox.qml
+++ b/src/quickcontrols/ios/SpinBox.qml
@@ -53,8 +53,8 @@ T.SpinBox {
states: [
{"up": true},
{"pressed": control.up.pressed},
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
@@ -69,8 +69,8 @@ T.SpinBox {
states: [
{"down": true},
{"pressed": control.down.pressed},
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
@@ -87,8 +87,8 @@ T.SpinBox {
y: (parent.height - height) / 2
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
diff --git a/src/quickcontrols/ios/SwipeDelegate.qml b/src/quickcontrols/ios/SwipeDelegate.qml
index 9c6a4c3703..724de07959 100644
--- a/src/quickcontrols/ios/SwipeDelegate.qml
+++ b/src/quickcontrols/ios/SwipeDelegate.qml
@@ -39,7 +39,7 @@ T.SwipeDelegate {
background: Rectangle {
implicitHeight: 44
- color: Qt.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
+ color: Application.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
NinePatchImage {
property real offset: control.icon.source.toString() !== "" ? control.icon.width + control.spacing : 0
x: control.down ? 0 : control.leftPadding + offset
@@ -49,8 +49,8 @@ T.SwipeDelegate {
source: IOS.url + "itemdelegate-background"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"pressed": control.down}
]
}
diff --git a/src/quickcontrols/ios/Switch.qml b/src/quickcontrols/ios/Switch.qml
index 1b219cddf4..7a9b029fdf 100644
--- a/src/quickcontrols/ios/Switch.qml
+++ b/src/quickcontrols/ios/Switch.qml
@@ -32,8 +32,8 @@ T.Switch {
source: IOS.url + "switch-indicator"
ImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"checked": control.checked}
]
}
@@ -53,8 +53,8 @@ T.Switch {
source: IOS.url + "switch-handle"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"disabled": !control.enabled}
]
}
diff --git a/src/quickcontrols/ios/SwitchDelegate.qml b/src/quickcontrols/ios/SwitchDelegate.qml
index 4b7d8bdccf..80e79580de 100644
--- a/src/quickcontrols/ios/SwitchDelegate.qml
+++ b/src/quickcontrols/ios/SwitchDelegate.qml
@@ -33,8 +33,8 @@ T.SwitchDelegate {
source: IOS.url + "switch-indicator"
ImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"checked": control.checked}
]
}
@@ -54,8 +54,8 @@ T.SwitchDelegate {
source: IOS.url + "switch-handle"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
{"disabled": !control.enabled}
]
}
@@ -84,7 +84,7 @@ T.SwitchDelegate {
background: Rectangle {
implicitHeight: 44
- color: Qt.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
+ color: Application.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
NinePatchImage {
property real offset: control.icon.source.toString() !== "" ? control.icon.width + control.spacing : 0
x: control.leftPadding + offset
@@ -93,8 +93,8 @@ T.SwitchDelegate {
source: IOS.url + "itemdelegate-background"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
]
}
}
diff --git a/src/quickcontrols/ios/TabBar.qml b/src/quickcontrols/ios/TabBar.qml
index 0f42ea14e5..99434fa14d 100644
--- a/src/quickcontrols/ios/TabBar.qml
+++ b/src/quickcontrols/ios/TabBar.qml
@@ -32,7 +32,7 @@ T.TabBar {
background: Rectangle {
implicitHeight: 49
- color: Qt.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
+ color: Application.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
Rectangle {
height: 1
width: parent.width
diff --git a/src/quickcontrols/ios/ToolBar.qml b/src/quickcontrols/ios/ToolBar.qml
index 28b0029018..0c02403630 100644
--- a/src/quickcontrols/ios/ToolBar.qml
+++ b/src/quickcontrols/ios/ToolBar.qml
@@ -15,7 +15,7 @@ T.ToolBar {
background: Rectangle {
implicitHeight: 49
- color: Qt.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
+ color: Application.styleHints.colorScheme === Qt.Dark ? control.palette.light : control.palette.base
Rectangle {
height: 1
width: parent.width
diff --git a/src/quickcontrols/ios/ToolTip.qml b/src/quickcontrols/ios/ToolTip.qml
index 973e819503..8e6502da98 100644
--- a/src/quickcontrols/ios/ToolTip.qml
+++ b/src/quickcontrols/ios/ToolTip.qml
@@ -45,8 +45,8 @@ T.ToolTip {
source: IOS.url + "tooltip-background"
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
diff --git a/src/quickcontrols/ios/TreeViewDelegate.qml b/src/quickcontrols/ios/TreeViewDelegate.qml
index 5fc16bee07..7277011613 100644
--- a/src/quickcontrols/ios/TreeViewDelegate.qml
+++ b/src/quickcontrols/ios/TreeViewDelegate.qml
@@ -46,8 +46,8 @@ T.TreeViewDelegate {
source: IOS.url + "arrow-indicator"
ImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
@@ -55,15 +55,15 @@ T.TreeViewDelegate {
background: Rectangle {
implicitHeight: 44
- color: Qt.styleHints.colorScheme === Qt.Dark ? control.palette.dark : control.palette.base
+ color: Application.styleHints.colorScheme === Qt.Dark ? control.palette.dark : control.palette.base
NinePatchImage {
height: parent.height
width: parent.width
source: IOS.url + (control.highlighted ? "itemdelegate-background-pressed" : "itemdelegate-background")
NinePatchImageSelector on source {
states: [
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark}
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark}
]
}
}
diff --git a/src/quickcontrols/ios/impl/DialogButtonBoxDelegate.qml b/src/quickcontrols/ios/impl/DialogButtonBoxDelegate.qml
index 2be1f9535e..0018737790 100644
--- a/src/quickcontrols/ios/impl/DialogButtonBoxDelegate.qml
+++ b/src/quickcontrols/ios/impl/DialogButtonBoxDelegate.qml
@@ -21,7 +21,7 @@ Button {
flat: true
contentItem: IconLabel {
- readonly property var redColor: Qt.styleHints.colorScheme === Qt.Light ? "#ff3b30" : "#ff453a"
+ readonly property var redColor: Application.styleHints.colorScheme === Qt.Light ? "#ff3b30" : "#ff453a"
text: delegate.text
font: delegate.font
spacing: delegate.spacing
@@ -57,8 +57,8 @@ Button {
{"vertical": delegate.hasVerticalLayout},
{"last": delegate.hasVerticalLayout && delegate.isLastItem},
{"pressed": delegate.down},
- {"light": Qt.styleHints.colorScheme === Qt.Light},
- {"dark": Qt.styleHints.colorScheme === Qt.Dark},
+ {"light": Application.styleHints.colorScheme === Qt.Light},
+ {"dark": Application.styleHints.colorScheme === Qt.Dark},
]
}
}
diff --git a/src/quickcontrols/macos/BusyIndicator.qml b/src/quickcontrols/macos/BusyIndicator.qml
index c74e215f36..8c9dadf110 100644
--- a/src/quickcontrols/macos/BusyIndicator.qml
+++ b/src/quickcontrols/macos/BusyIndicator.qml
@@ -26,7 +26,7 @@ T.BusyIndicator {
contentItem: AnimatedImage {
source: "qrc:/qt-project.org/imports/QtQuick/Controls/macOS/images/busyindicator-"
- + (Qt.styleHints.colorScheme === Qt.Light ? "light" : "dark") + ".webp"
+ + (Application.styleHints.colorScheme === Qt.Light ? "light" : "dark") + ".webp"
opacity: control.running ? 1 : 0
playing: control.running || opacity > 0
visible: control.running || opacity > 0
diff --git a/src/quickcontrols/macos/CMakeLists.txt b/src/quickcontrols/macos/CMakeLists.txt
index 376c093f27..4c3ff540a4 100644
--- a/src/quickcontrols/macos/CMakeLists.txt
+++ b/src/quickcontrols/macos/CMakeLists.txt
@@ -5,6 +5,8 @@
## qtquickcontrols2macosstyleplugin Plugin:
#####################################################################
+add_subdirectory(impl)
+
set(qml_files
"BusyIndicator.qml"
"Button.qml"
@@ -18,11 +20,17 @@ set(qml_files
"Frame.qml"
"GroupBox.qml"
"ItemDelegate.qml"
+ "Menu.qml"
+ "MenuBar.qml"
+ "MenuBarItem.qml"
+ "MenuItem.qml"
+ "MenuSeparator.qml"
"ProgressBar.qml"
"RadioButton.qml"
"RadioDelegate.qml"
"RangeSlider.qml"
"ScrollBar.qml"
+ "ScrollIndicator.qml"
"ScrollView.qml"
"SelectionRectangle.qml"
"Slider.qml"
@@ -60,6 +68,12 @@ qt_internal_add_qml_module(qtquickcontrols2macosstyleplugin
images/busyindicator-light.webp
images/busyindicator-light@2x.webp
images/busyindicator-light@3x.webp
+ images/checkmark.png
+ images/checkmark@2x.png
+ images/checkmark@3x.png
+ images/menuarrow.png
+ images/menuarrow@2x.png
+ images/menuarrow@3x.png
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
@@ -73,8 +87,6 @@ qt_internal_add_qml_module(qtquickcontrols2macosstyleplugin
Qt::QuickTemplates2Private
)
-add_subdirectory(impl)
-
# Native style is a dependency of the macOS style.
_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2macosstyleplugin
qtquickcontrols2nativestyleplugin)
diff --git a/src/quickcontrols/macos/DelayButton.qml b/src/quickcontrols/macos/DelayButton.qml
index 3e0193c2e2..cd7b7b64ac 100644
--- a/src/quickcontrols/macos/DelayButton.qml
+++ b/src/quickcontrols/macos/DelayButton.qml
@@ -57,11 +57,11 @@ T.DelayButton {
// Delay progress bar.
Rectangle {
x: (parent.width - parent.implicitWidth) / 2
- y: parent.height + (Qt.styleHints.colorScheme === Qt.Light ? 1 : 0)
+ y: parent.height + (Application.styleHints.colorScheme === Qt.Light ? 1 : 0)
width: control.progress * parent.implicitWidth
// The bar is too thick for the light theme at 2 pixels,
// but too thin for the dark theme at 1.
- height: Qt.styleHints.colorScheme === Qt.Light ? 1 : 2
+ height: Application.styleHints.colorScheme === Qt.Light ? 1 : 2
color: control.palette.accent
scale: control.mirrored ? -1 : 1
}
diff --git a/src/quickcontrols/macos/Menu.qml b/src/quickcontrols/macos/Menu.qml
new file mode 100644
index 0000000000..28f86ca1f0
--- /dev/null
+++ b/src/quickcontrols/macos/Menu.qml
@@ -0,0 +1,83 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Window
+import QtQuick.Effects
+
+T.Menu {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ // The insets are found by examining the MultiEffect.itemRect, which
+ // contains the drop shadow offsets. Note: the insets are hard-coded
+ // to avoid a binding loop to implicit size.
+ leftInset: -32
+ topInset: -32
+ rightInset: -32
+ bottomInset: -32
+ leftPadding: 5
+ topPadding: 5
+ rightPadding: 5
+ bottomPadding: 5
+ margins: 0
+ overlap: 4
+
+ delegate: MenuItem { }
+
+ contentItem: ListView {
+ implicitHeight: contentHeight
+ model: control.contentModel
+ interactive: Window.window
+ ? contentHeight + control.topPadding + control.bottomPadding > control.height
+ : false
+ currentIndex: control.currentIndex
+ spacing: 2
+
+ ScrollIndicator.vertical: ScrollIndicator {}
+ }
+
+ background: Item {
+ implicitWidth: 200 - control.leftInset - control.rightInset
+ implicitHeight: 20 - control.topInset - control.bottomInset
+ MultiEffect {
+ x: -control.leftInset
+ y: -control.topInset
+ width: source.width
+ height: source.height
+ source: Rectangle {
+ width: control.background.width + control.leftInset + control.rightInset
+ height: control.background.height + control.topInset + control.bottomInset
+ radius: 5
+ color: Application.styleHints.colorScheme === Qt.Light
+ ? Qt.darker(control.palette.window, 1.04)
+ : Qt.darker(control.palette.window, 1.2)
+ border.color: Application.styleHints.colorScheme === Qt.Light
+ ? Qt.darker(control.palette.window, 1.4)
+ : Qt.lighter(control.palette.window, 2.0)
+ border.width: 0.5
+ visible: false
+ }
+ shadowScale: 1.04
+ shadowOpacity: Application.styleHints.colorScheme === Qt.Light ? 0.15 : 0.2
+ shadowColor: 'black'
+ shadowEnabled: true
+ shadowHorizontalOffset: 0
+ shadowVerticalOffset: 7
+ }
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: "transparent"
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: "transparent"
+ }
+}
diff --git a/src/quickcontrols/macos/MenuBar.qml b/src/quickcontrols/macos/MenuBar.qml
new file mode 100644
index 0000000000..2b1e63fc30
--- /dev/null
+++ b/src/quickcontrols/macos/MenuBar.qml
@@ -0,0 +1,35 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.MenuBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ leftPadding: 6
+ rightPadding: 6
+ topPadding: 3
+ bottomPadding: 2
+ spacing: 4
+
+ delegate: MenuBarItem { }
+
+ contentItem: Row {
+ spacing: control.spacing
+ Repeater {
+ model: control.contentModel
+ }
+ }
+
+ background: Rectangle {
+ implicitHeight: 20
+ color: control.palette.window // window title bar color
+ }
+}
diff --git a/src/quickcontrols/macos/MenuBarItem.qml b/src/quickcontrols/macos/MenuBarItem.qml
new file mode 100644
index 0000000000..de7db7fd91
--- /dev/null
+++ b/src/quickcontrols/macos/MenuBarItem.qml
@@ -0,0 +1,46 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.MenuBarItem {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ leftInset: -4
+ rightInset: -4
+ padding: 6
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ background: Rectangle {
+ implicitWidth: 20
+ implicitHeight: 20
+
+ color: "black"
+ opacity: 0.1
+ radius: 4
+ visible: control.down || control.highlighted
+ }
+}
diff --git a/src/quickcontrols/macos/MenuItem.qml b/src/quickcontrols/macos/MenuItem.qml
new file mode 100644
index 0000000000..109c61e6a8
--- /dev/null
+++ b/src/quickcontrols/macos/MenuItem.qml
@@ -0,0 +1,75 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.macOS.impl
+
+T.MenuItem {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ leftPadding: 10
+ rightPadding: 10
+ topPadding: 3
+ bottomPadding: 3
+ spacing: 0
+
+ icon.width: 16
+ icon.height: 16
+
+ implicitTextPadding: control.checkable && control.indicator ? control.indicator.width + control.spacing : 0
+
+ contentItem: IconLabel {
+ readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0
+ leftPadding: !control.mirrored ? control.textPadding : arrowPadding
+ rightPadding: control.mirrored ? control.textPadding : arrowPadding
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.down || control.highlighted ? "white" : control.palette.text
+ }
+
+ arrow: ColorImage {
+ x: control.mirrored ? control.padding : control.width - width - control.padding
+ y: control.topPadding + (control.availableHeight - height) / 2
+ width: 20
+
+ visible: control.subMenu
+ rotation: control.mirrored ? -180 : 0
+ scale: 0.6
+ color: control.palette.text
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/macOS/images/menuarrow.png"
+ fillMode: Image.Pad
+ }
+
+ indicator: CheckIndicator {
+ x: control.mirrored ? control.width - width - control.rightPadding : control.leftPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ control: control
+ visible: control.checkable
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 25
+ radius: 4
+
+ color: control.palette.accent
+ opacity: 0.7
+ visible: control.down || control.highlighted
+ }
+}
diff --git a/src/quickcontrols/macos/MenuSeparator.qml b/src/quickcontrols/macos/MenuSeparator.qml
new file mode 100644
index 0000000000..e9c0454ee6
--- /dev/null
+++ b/src/quickcontrols/macos/MenuSeparator.qml
@@ -0,0 +1,24 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.MenuSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ horizontalPadding: 0
+ verticalPadding: 2
+
+ contentItem: Rectangle {
+ implicitWidth: 188
+ implicitHeight: 1
+ opacity: 0.7
+ color: palette.disabled.buttonText
+ }
+}
diff --git a/src/quickcontrols/macos/RangeSlider.qml b/src/quickcontrols/macos/RangeSlider.qml
index da3fe83cf2..897e23eedc 100644
--- a/src/quickcontrols/macos/RangeSlider.qml
+++ b/src/quickcontrols/macos/RangeSlider.qml
@@ -65,9 +65,9 @@ T.RangeSlider {
height: parent.height
radius: parent.radius
// No border in dark mode, instead we fill.
- color: Qt.styleHints.colorScheme === Qt.Light
+ color: Application.styleHints.colorScheme === Qt.Light
? "transparent" : Qt.lighter(control.palette.window, 1.6)
- border.color: Qt.styleHints.colorScheme === Qt.Light
+ border.color: Application.styleHints.colorScheme === Qt.Light
? Qt.darker(control.palette.window, 1.1)
: "transparent"
@@ -79,7 +79,7 @@ T.RangeSlider {
radius: parent.radius
color: "transparent"
border.color: Qt.darker(control.palette.window, 1.05)
- visible: Qt.styleHints.colorScheme === Qt.Light
+ visible: Application.styleHints.colorScheme === Qt.Light
}
}
}
diff --git a/src/quickcontrols/macos/ScrollIndicator.qml b/src/quickcontrols/macos/ScrollIndicator.qml
new file mode 100644
index 0000000000..f8358eb1bf
--- /dev/null
+++ b/src/quickcontrols/macos/ScrollIndicator.qml
@@ -0,0 +1,42 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.ScrollIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 2
+
+ contentItem: Rectangle {
+ implicitWidth: 2
+ implicitHeight: 2
+
+ color: control.palette.mid
+ visible: control.size < 1.0
+ opacity: 0.0
+
+ states: State {
+ name: "active"
+ when: control.active
+ PropertyChanges { control.contentItem.opacity: 0.75 }
+ }
+
+ transitions: [
+ Transition {
+ from: "active"
+ SequentialAnimation {
+ PauseAnimation { duration: 450 }
+ NumberAnimation { target: control.contentItem; duration: 200; property: "opacity"; to: 0.0 }
+ }
+ }
+ ]
+ }
+}
diff --git a/src/quickcontrols/macos/images/checkmark.png b/src/quickcontrols/macos/images/checkmark.png
new file mode 100644
index 0000000000..c89fae5252
--- /dev/null
+++ b/src/quickcontrols/macos/images/checkmark.png
Binary files differ
diff --git a/src/quickcontrols/macos/images/checkmark@2x.png b/src/quickcontrols/macos/images/checkmark@2x.png
new file mode 100644
index 0000000000..9fdaa3285f
--- /dev/null
+++ b/src/quickcontrols/macos/images/checkmark@2x.png
Binary files differ
diff --git a/src/quickcontrols/macos/images/checkmark@3x.png b/src/quickcontrols/macos/images/checkmark@3x.png
new file mode 100644
index 0000000000..cc383aa5c0
--- /dev/null
+++ b/src/quickcontrols/macos/images/checkmark@3x.png
Binary files differ
diff --git a/src/quickcontrols/macos/images/menuarrow.png b/src/quickcontrols/macos/images/menuarrow.png
new file mode 100644
index 0000000000..4c5ac65585
--- /dev/null
+++ b/src/quickcontrols/macos/images/menuarrow.png
Binary files differ
diff --git a/src/quickcontrols/macos/images/menuarrow@2x.png b/src/quickcontrols/macos/images/menuarrow@2x.png
new file mode 100644
index 0000000000..6cfa8a1883
--- /dev/null
+++ b/src/quickcontrols/macos/images/menuarrow@2x.png
Binary files differ
diff --git a/src/quickcontrols/macos/images/menuarrow@3x.png b/src/quickcontrols/macos/images/menuarrow@3x.png
new file mode 100644
index 0000000000..1a6334e0d0
--- /dev/null
+++ b/src/quickcontrols/macos/images/menuarrow@3x.png
Binary files differ
diff --git a/src/quickcontrols/macos/impl/CMakeLists.txt b/src/quickcontrols/macos/impl/CMakeLists.txt
index 6d007f4d9f..f10db451bc 100644
--- a/src/quickcontrols/macos/impl/CMakeLists.txt
+++ b/src/quickcontrols/macos/impl/CMakeLists.txt
@@ -2,6 +2,7 @@
# SPDX-License-Identifier: BSD-3-Clause
set(qml_files
+ "CheckIndicator.qml"
"SwitchHandle.qml"
"SwitchIndicator.qml"
)
diff --git a/src/quickcontrols/macos/impl/CheckIndicator.qml b/src/quickcontrols/macos/impl/CheckIndicator.qml
new file mode 100644
index 0000000000..9a41895475
--- /dev/null
+++ b/src/quickcontrols/macos/impl/CheckIndicator.qml
@@ -0,0 +1,21 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+
+Item {
+ id: indicator
+ implicitWidth: 14
+ implicitHeight: 10
+
+ property Item control
+
+ ColorImage {
+ y: (parent.height - height) / 2
+ color: control.palette.text
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/macOS/images/checkmark.png"
+ visible: indicator.control.checkState === Qt.Checked
+ || (indicator.control.checked && indicator.control.checkState === undefined)
+ }
+}
diff --git a/src/quickcontrols/macos/impl/SwitchHandle.qml b/src/quickcontrols/macos/impl/SwitchHandle.qml
index 3ef17410e4..3f2f01e87a 100644
--- a/src/quickcontrols/macos/impl/SwitchHandle.qml
+++ b/src/quickcontrols/macos/impl/SwitchHandle.qml
@@ -10,7 +10,7 @@ Rectangle {
width: 20
height: 20
radius: 10
- color: Qt.styleHints.colorScheme === Qt.Light
+ color: Application.styleHints.colorScheme === Qt.Light
? Qt.darker(palette.base, down ? 1.05 : 1)
: Qt.lighter("#cdcbc9", down ? 1.05 : 1)
diff --git a/src/quickcontrols/macos/impl/SwitchIndicator.qml b/src/quickcontrols/macos/impl/SwitchIndicator.qml
index 33b6f5ca5f..53bd61c2ab 100644
--- a/src/quickcontrols/macos/impl/SwitchIndicator.qml
+++ b/src/quickcontrols/macos/impl/SwitchIndicator.qml
@@ -16,7 +16,7 @@ Rectangle {
// For QQuickMacFocusFrame.
readonly property real __focusFrameRadius: radius
- color: Qt.styleHints.colorScheme === Qt.Light
+ color: Application.styleHints.colorScheme === Qt.Light
? Qt.darker(indicator.control.checked
? indicator.palette.accent : "#d9d6d2", indicator.control.down ? indicator.downTintFactor : 1)
: Qt.lighter(indicator.control.checked
@@ -32,7 +32,7 @@ Rectangle {
// the ColorAnimation to happen when changing checked state.
PropertyChanges {
target: indicator
- color: Qt.styleHints.colorScheme === Qt.Light
+ color: Application.styleHints.colorScheme === Qt.Light
? indicator.control.checked ? indicator.palette.accent : "#d9d6d2"
: indicator.control.checked ? indicator.palette.accent : "#454545"
}
@@ -57,7 +57,7 @@ Rectangle {
height: parent.height
radius: height / 2
color: "transparent"
- border.color: Qt.styleHints.colorScheme === Qt.Light
+ border.color: Application.styleHints.colorScheme === Qt.Light
? Qt.darker("#06000000", indicator.control.down ? indicator.downTintFactor : 1)
: Qt.lighter("#1affffff", indicator.control.down ? indicator.downTintFactor : 1)
@@ -68,7 +68,7 @@ Rectangle {
implicitHeight: parent.height - 2
radius: parent.radius
color: "transparent"
- border.color: Qt.styleHints.colorScheme === Qt.Light
+ border.color: Application.styleHints.colorScheme === Qt.Light
? Qt.darker("#02000000", indicator.control.down ? indicator.downTintFactor : 1)
: Qt.lighter("#04ffffff", indicator.control.down ? indicator.downTintFactor : 1)
}
diff --git a/src/quickcontrols/material/Button.qml b/src/quickcontrols/material/Button.qml
index c02d9f426a..8ffe07bbc3 100644
--- a/src/quickcontrols/material/Button.qml
+++ b/src/quickcontrols/material/Button.qml
@@ -18,8 +18,9 @@ T.Button {
topInset: 6
bottomInset: 6
verticalPadding: Material.buttonVerticalPadding
- leftPadding: Material.buttonLeftPadding(flat, hasIcon)
- rightPadding: Material.buttonRightPadding(flat, hasIcon, text !== "")
+ leftPadding: Material.buttonLeftPadding(flat, hasIcon && (display !== AbstractButton.TextOnly))
+ rightPadding: Material.buttonRightPadding(flat, hasIcon && (display !== AbstractButton.TextOnly),
+ (text !== "") && (display !== AbstractButton.IconOnly))
spacing: 8
icon.width: 24
diff --git a/src/quickcontrols/material/CMakeLists.txt b/src/quickcontrols/material/CMakeLists.txt
index a427b3711c..0c7416ea7f 100644
--- a/src/quickcontrols/material/CMakeLists.txt
+++ b/src/quickcontrols/material/CMakeLists.txt
@@ -125,7 +125,6 @@ qt_internal_add_qml_module(QuickControls2Material
Qt::QuickControls2Private
Qt::QuickPrivate
Qt::QuickTemplates2Private
- GENERATE_CPP_EXPORTS
)
target_sources(qtquickcontrols2materialstyleplugin
diff --git a/src/quickcontrols/material/Dialog.qml b/src/quickcontrols/material/Dialog.qml
index 014fcc67c5..26f8848edc 100644
--- a/src/quickcontrols/material/Dialog.qml
+++ b/src/quickcontrols/material/Dialog.qml
@@ -44,7 +44,7 @@ T.Dialog {
background: Rectangle {
// FullScale doesn't make sense for Dialog.
- radius: control.Material.roundedScale
+ radius: parent?.parent === Overlay.overlay ? control.Material.roundedScale : 0
color: control.Material.dialogColor
layer.enabled: control.Material.elevation > 0
@@ -56,7 +56,7 @@ T.Dialog {
header: Label {
text: control.title
- visible: control.title
+ visible: parent?.parent === Overlay.overlay && control.title
elide: Label.ElideRight
padding: 24
bottomPadding: 0
diff --git a/src/quickcontrols/material/Tumbler.qml b/src/quickcontrols/material/Tumbler.qml
index 59320cf52b..48d0c2e739 100644
--- a/src/quickcontrols/material/Tumbler.qml
+++ b/src/quickcontrols/material/Tumbler.qml
@@ -14,6 +14,8 @@ T.Tumbler {
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
+ readonly property real __delegateHeight: availableHeight / visibleItemCount
+
delegate: Text {
text: modelData
color: control.Material.foreground
@@ -33,13 +35,11 @@ T.Tumbler {
delegate: control.delegate
path: Path {
startX: control.contentItem.width / 2
- startY: -control.contentItem.delegateHeight / 2
+ startY: -control.__delegateHeight / 2
PathLine {
x: control.contentItem.width / 2
- y: (control.visibleItemCount + 1) * control.contentItem.delegateHeight - control.contentItem.delegateHeight / 2
+ y: (control.visibleItemCount + 1) * control.__delegateHeight - control.__delegateHeight / 2
}
}
-
- property real delegateHeight: control.availableHeight / control.visibleItemCount
}
}
diff --git a/src/quickcontrols/material/impl/CursorDelegate.qml b/src/quickcontrols/material/impl/CursorDelegate.qml
index 811aa89e36..d1ef157f87 100644
--- a/src/quickcontrols/material/impl/CursorDelegate.qml
+++ b/src/quickcontrols/material/impl/CursorDelegate.qml
@@ -24,7 +24,7 @@ Rectangle {
id: timer
running: cursor.parent.activeFocus && !cursor.parent.readOnly && interval != 0
repeat: true
- interval: Qt.styleHints.cursorFlashTime / 2
+ interval: Application.styleHints.cursorFlashTime / 2
onTriggered: cursor.opacity = !cursor.opacity ? 1 : 0
// force the cursor visible when gaining focus
onRunningChanged: cursor.opacity = 1
diff --git a/src/quickcontrols/qquickattachedpropertypropagator.cpp b/src/quickcontrols/qquickattachedpropertypropagator.cpp
index cf752a4248..e481fafabe 100644
--- a/src/quickcontrols/qquickattachedpropertypropagator.cpp
+++ b/src/quickcontrols/qquickattachedpropertypropagator.cpp
@@ -12,7 +12,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcAttached, "qt.quick.controls.attachedpropertypropagator")
+Q_STATIC_LOGGING_CATEGORY(lcAttached, "qt.quick.controls.attachedpropertypropagator")
/*!
\class QQuickAttachedPropertyPropagator
diff --git a/src/quickcontrols/qquickstyle.cpp b/src/quickcontrols/qquickstyle.cpp
index a40e9535e2..7ac62244ce 100644
--- a/src/quickcontrols/qquickstyle.cpp
+++ b/src/quickcontrols/qquickstyle.cpp
@@ -27,7 +27,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQtQuickControlsStyle, "qt.quick.controls.style")
+Q_STATIC_LOGGING_CATEGORY(lcQtQuickControlsStyle, "qt.quick.controls.style")
/*!
\class QQuickStyle
@@ -400,6 +400,7 @@ QStringList QQuickStylePrivate::builtInStyles()
return {
QLatin1String("Basic"),
QLatin1String("Fusion"),
+ QLatin1String("FluentWinUI3"),
QLatin1String("Imagine"),
#ifdef Q_OS_MACOS
QLatin1String("macOS"),
diff --git a/src/quickcontrols/qquickstyleplugin.cpp b/src/quickcontrols/qquickstyleplugin.cpp
index caae034970..a3afca2336 100644
--- a/src/quickcontrols/qquickstyleplugin.cpp
+++ b/src/quickcontrols/qquickstyleplugin.cpp
@@ -16,7 +16,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcStylePlugin, "qt.quick.controls.styleplugin")
+Q_STATIC_LOGGING_CATEGORY(lcStylePlugin, "qt.quick.controls.styleplugin")
QQuickStylePlugin::QQuickStylePlugin(QObject *parent)
: QQmlExtensionPlugin(parent)
diff --git a/src/quickcontrols/qt_cmdline.cmake b/src/quickcontrols/qt_cmdline.cmake
index ed009c5407..6160f818f4 100644
--- a/src/quickcontrols/qt_cmdline.cmake
+++ b/src/quickcontrols/qt_cmdline.cmake
@@ -2,6 +2,7 @@
# SPDX-License-Identifier: BSD-3-Clause
qt_commandline_option(style-fusion TYPE boolean NAME quickcontrols2-fusion)
+qt_commandline_option(style-fluentwinui3 TYPE boolean NAME quickcontrols2-fluentwinui3)
qt_commandline_option(style-imagine TYPE boolean NAME quickcontrols2-imagine)
qt_commandline_option(style-ios TYPE boolean NAME quickcontrols2-ios)
qt_commandline_option(style-material TYPE boolean NAME quickcontrols2-material)
diff --git a/src/quickcontrols/universal/CMakeLists.txt b/src/quickcontrols/universal/CMakeLists.txt
index b9ab5d9aaa..264c7255d3 100644
--- a/src/quickcontrols/universal/CMakeLists.txt
+++ b/src/quickcontrols/universal/CMakeLists.txt
@@ -123,7 +123,6 @@ qt_internal_add_qml_module(QuickControls2Universal
Qt::QuickControls2UniversalStyleImpl
Qt::QuickPrivate
Qt::QuickTemplates2Private
- GENERATE_CPP_EXPORTS
)
target_sources(qtquickcontrols2universalstyleplugin
diff --git a/src/quickcontrols/universal/Dialog.qml b/src/quickcontrols/universal/Dialog.qml
index 0ed4e673c7..1d21b48574 100644
--- a/src/quickcontrols/universal/Dialog.qml
+++ b/src/quickcontrols/universal/Dialog.qml
@@ -28,7 +28,7 @@ T.Dialog {
header: Label {
text: control.title
- visible: control.title
+ visible: parent?.parent === Overlay.overlay && control.title
elide: Label.ElideRight
topPadding: 18
leftPadding: 24
diff --git a/src/quickcontrols/universal/Tumbler.qml b/src/quickcontrols/universal/Tumbler.qml
index 03b5fcca63..e6d7da6e2c 100644
--- a/src/quickcontrols/universal/Tumbler.qml
+++ b/src/quickcontrols/universal/Tumbler.qml
@@ -14,6 +14,8 @@ T.Tumbler {
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
+ readonly property real __delegateHeight: availableHeight / visibleItemCount
+
delegate: Text {
text: modelData
font: control.font
@@ -33,10 +35,10 @@ T.Tumbler {
delegate: control.delegate
path: Path {
startX: control.contentItem.width / 2
- startY: -control.contentItem.delegateHeight / 2
+ startY: -control.__delegateHeight / 2
PathLine {
x: control.contentItem.width / 2
- y: (control.visibleItemCount + 1) * control.contentItem.delegateHeight - control.contentItem.delegateHeight / 2
+ y: (control.visibleItemCount + 1) * control.__delegateHeight - control.__delegateHeight / 2
}
}
diff --git a/src/quickcontrols/windows/CMakeLists.txt b/src/quickcontrols/windows/CMakeLists.txt
index 55c57a956c..36e871abdb 100644
--- a/src/quickcontrols/windows/CMakeLists.txt
+++ b/src/quickcontrols/windows/CMakeLists.txt
@@ -15,10 +15,16 @@ set(qml_files
"Frame.qml"
"GroupBox.qml"
"ItemDelegate.qml"
+ "Menu.qml"
+ "MenuBar.qml"
+ "MenuBarItem.qml"
+ "MenuItem.qml"
+ "MenuSeparator.qml"
"ProgressBar.qml"
"RadioButton.qml"
"RadioDelegate.qml"
"RangeSlider.qml"
+ "ScrollIndicator.qml"
"SelectionRectangle.qml"
"Slider.qml"
"SpinBox.qml"
@@ -44,6 +50,13 @@ qt_internal_add_qml_module(qtquickcontrols2windowsstyleplugin
qtquickcontrols2windowsstyleplugin.cpp
QML_FILES
${qml_files}
+ RESOURCES
+ images/checkmark.png
+ images/checkmark@2x.png
+ images/checkmark@3x.png
+ images/menuarrow.png
+ images/menuarrow@2x.png
+ images/menuarrow@3x.png
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
diff --git a/src/quickcontrols/windows/Menu.qml b/src/quickcontrols/windows/Menu.qml
new file mode 100644
index 0000000000..67801039cc
--- /dev/null
+++ b/src/quickcontrols/windows/Menu.qml
@@ -0,0 +1,78 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Window
+import QtQuick.Effects
+
+T.Menu {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ // The insets are found by examining the MultiEffect.itemRect, which
+ // contains the drop shadow offsets. Note: the insets are hard-coded
+ // to avoid a binding loop to implicit size.
+ leftInset: -32
+ topInset: -32
+ rightInset: -32
+ bottomInset: -32
+ leftPadding: 5
+ topPadding: 5
+ rightPadding: 5
+ bottomPadding: 5
+ margins: 0
+ overlap: 4
+
+ delegate: MenuItem { }
+
+ contentItem: ListView {
+ implicitHeight: contentHeight
+ model: control.contentModel
+ interactive: Window.window
+ ? contentHeight + control.topPadding + control.bottomPadding > control.height
+ : false
+ currentIndex: control.currentIndex
+ spacing: 2
+
+ ScrollIndicator.vertical: ScrollIndicator {}
+ }
+
+ background: Item {
+ implicitWidth: 200 - control.leftInset - control.rightInset
+ implicitHeight: 20 - control.topInset - control.bottomInset
+ MultiEffect {
+ x: -control.leftInset
+ y: -control.topInset
+ width: source.width
+ height: source.height
+ source: Rectangle {
+ width: control.background.width + control.leftInset + control.rightInset
+ height: control.background.height + control.topInset + control.bottomInset
+ radius: 8
+ color: Qt.lighter(control.palette.window, 1.15)
+ border.color: Qt.darker(control.palette.window, 1.12)
+ visible: false
+ }
+ shadowScale: 1.04
+ shadowOpacity: 0.1
+ shadowColor: 'black'
+ shadowEnabled: true
+ shadowHorizontalOffset: 0
+ shadowVerticalOffset: 10
+ }
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: "transparent"
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: "transparent"
+ }
+}
diff --git a/src/quickcontrols/windows/MenuBar.qml b/src/quickcontrols/windows/MenuBar.qml
new file mode 100644
index 0000000000..ec998abde7
--- /dev/null
+++ b/src/quickcontrols/windows/MenuBar.qml
@@ -0,0 +1,35 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.MenuBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ leftPadding: 3
+ rightPadding: 3
+ topPadding: 3
+ bottomPadding: 3
+ spacing: 10
+
+ delegate: MenuBarItem { }
+
+ contentItem: Row {
+ spacing: control.spacing
+ Repeater {
+ model: control.contentModel
+ }
+ }
+
+ background: Rectangle {
+ implicitHeight: 20
+ color: "white" // window title bar color
+ }
+}
diff --git a/src/quickcontrols/windows/MenuBarItem.qml b/src/quickcontrols/windows/MenuBarItem.qml
new file mode 100644
index 0000000000..fe71542153
--- /dev/null
+++ b/src/quickcontrols/windows/MenuBarItem.qml
@@ -0,0 +1,47 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.MenuBarItem {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ topPadding: 8
+ bottomPadding: 8
+ leftPadding: 10
+ rightPadding: 10
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ background: Rectangle {
+ implicitWidth: 20
+ implicitHeight: 20
+
+ color: "black"
+ opacity: 0.05
+ radius: 4
+ visible: control.down || control.highlighted
+ }
+}
diff --git a/src/quickcontrols/windows/MenuItem.qml b/src/quickcontrols/windows/MenuItem.qml
new file mode 100644
index 0000000000..0d3c4f89f6
--- /dev/null
+++ b/src/quickcontrols/windows/MenuItem.qml
@@ -0,0 +1,74 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Windows.impl
+
+T.MenuItem {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ leftPadding: 10
+ rightPadding: 10
+ topPadding: 3
+ bottomPadding: 3
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ implicitTextPadding: control.checkable && control.indicator ? control.indicator.width + control.spacing : 0
+
+ contentItem: IconLabel {
+ readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0
+ leftPadding: !control.mirrored ? control.textPadding : arrowPadding
+ rightPadding: control.mirrored ? control.textPadding : arrowPadding
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ arrow: ColorImage {
+ x: control.mirrored ? control.padding : control.width - width - control.padding
+ y: control.topPadding + (control.availableHeight - height) / 2
+ width: 20
+
+ visible: control.subMenu
+ rotation: control.mirrored ? -180 : 0
+ color: control.palette.text
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Windows/images/menuarrow.png"
+ fillMode: Image.Pad
+ }
+
+ indicator: CheckIndicator {
+ x: control.mirrored ? control.width - width - control.rightPadding : control.leftPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ control: control
+ visible: control.checkable
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 30
+ radius: 4
+
+ color: control.palette.dark
+ opacity: 0.1
+ visible: control.down || control.highlighted
+ }
+}
diff --git a/src/quickcontrols/windows/MenuSeparator.qml b/src/quickcontrols/windows/MenuSeparator.qml
new file mode 100644
index 0000000000..6559be9958
--- /dev/null
+++ b/src/quickcontrols/windows/MenuSeparator.qml
@@ -0,0 +1,23 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.MenuSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ horizontalPadding: 0
+ verticalPadding: 2
+
+ contentItem: Rectangle {
+ implicitWidth: 188
+ implicitHeight: 1
+ color: control.palette.midlight
+ }
+}
diff --git a/src/quickcontrols/windows/RangeSlider.qml b/src/quickcontrols/windows/RangeSlider.qml
index a124163e7b..c4eb1fc2cf 100644
--- a/src/quickcontrols/windows/RangeSlider.qml
+++ b/src/quickcontrols/windows/RangeSlider.qml
@@ -76,9 +76,9 @@ T.RangeSlider {
height: parent.height
radius: parent.radius
// No border in dark mode, instead we fill.
- color: Qt.styleHints.colorScheme === Qt.Light
+ color: Application.styleHints.colorScheme === Qt.Light
? "transparent" : Qt.lighter(control.palette.window, 1.6)
- border.color: Qt.styleHints.colorScheme === Qt.Light
+ border.color: Application.styleHints.colorScheme === Qt.Light
? Qt.darker(control.palette.window, 1.1)
: "transparent"
}
diff --git a/src/quickcontrols/windows/ScrollIndicator.qml b/src/quickcontrols/windows/ScrollIndicator.qml
new file mode 100644
index 0000000000..f8358eb1bf
--- /dev/null
+++ b/src/quickcontrols/windows/ScrollIndicator.qml
@@ -0,0 +1,42 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.ScrollIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 2
+
+ contentItem: Rectangle {
+ implicitWidth: 2
+ implicitHeight: 2
+
+ color: control.palette.mid
+ visible: control.size < 1.0
+ opacity: 0.0
+
+ states: State {
+ name: "active"
+ when: control.active
+ PropertyChanges { control.contentItem.opacity: 0.75 }
+ }
+
+ transitions: [
+ Transition {
+ from: "active"
+ SequentialAnimation {
+ PauseAnimation { duration: 450 }
+ NumberAnimation { target: control.contentItem; duration: 200; property: "opacity"; to: 0.0 }
+ }
+ }
+ ]
+ }
+}
diff --git a/src/quickcontrols/windows/images/checkmark.png b/src/quickcontrols/windows/images/checkmark.png
new file mode 100644
index 0000000000..35fe52c8c0
--- /dev/null
+++ b/src/quickcontrols/windows/images/checkmark.png
Binary files differ
diff --git a/src/quickcontrols/windows/images/checkmark@2x.png b/src/quickcontrols/windows/images/checkmark@2x.png
new file mode 100644
index 0000000000..fb7096b4b5
--- /dev/null
+++ b/src/quickcontrols/windows/images/checkmark@2x.png
Binary files differ
diff --git a/src/quickcontrols/windows/images/checkmark@3x.png b/src/quickcontrols/windows/images/checkmark@3x.png
new file mode 100644
index 0000000000..e0c2790607
--- /dev/null
+++ b/src/quickcontrols/windows/images/checkmark@3x.png
Binary files differ
diff --git a/src/quickcontrols/windows/images/menuarrow.png b/src/quickcontrols/windows/images/menuarrow.png
new file mode 100644
index 0000000000..b504351fe1
--- /dev/null
+++ b/src/quickcontrols/windows/images/menuarrow.png
Binary files differ
diff --git a/src/quickcontrols/windows/images/menuarrow@2x.png b/src/quickcontrols/windows/images/menuarrow@2x.png
new file mode 100644
index 0000000000..fa9082d0c0
--- /dev/null
+++ b/src/quickcontrols/windows/images/menuarrow@2x.png
Binary files differ
diff --git a/src/quickcontrols/windows/images/menuarrow@3x.png b/src/quickcontrols/windows/images/menuarrow@3x.png
new file mode 100644
index 0000000000..acb626246d
--- /dev/null
+++ b/src/quickcontrols/windows/images/menuarrow@3x.png
Binary files differ
diff --git a/src/quickcontrols/windows/impl/CMakeLists.txt b/src/quickcontrols/windows/impl/CMakeLists.txt
index fb1b0f2358..8b031b7a8d 100644
--- a/src/quickcontrols/windows/impl/CMakeLists.txt
+++ b/src/quickcontrols/windows/impl/CMakeLists.txt
@@ -2,6 +2,7 @@
# SPDX-License-Identifier: BSD-3-Clause
set(qml_files
+ "CheckIndicator.qml"
"SwitchIndicator.qml"
)
diff --git a/src/quickcontrols/windows/impl/CheckIndicator.qml b/src/quickcontrols/windows/impl/CheckIndicator.qml
new file mode 100644
index 0000000000..818336dfdf
--- /dev/null
+++ b/src/quickcontrols/windows/impl/CheckIndicator.qml
@@ -0,0 +1,21 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls.impl
+
+Item {
+ id: indicator
+ implicitWidth: 14
+ implicitHeight: 10
+
+ property Item control
+
+ ColorImage {
+ y: (parent.height - height) / 2
+ color: control.palette.text
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Windows/images/checkmark.png"
+ visible: indicator.control.checkState === Qt.Checked
+ || (indicator.control.checked && indicator.control.checkState === undefined)
+ }
+}
diff --git a/src/quickcontrolsimpl/CMakeLists.txt b/src/quickcontrolsimpl/CMakeLists.txt
index 5b8d932384..f50e671ce9 100644
--- a/src/quickcontrolsimpl/CMakeLists.txt
+++ b/src/quickcontrolsimpl/CMakeLists.txt
@@ -44,7 +44,6 @@ qt_internal_add_qml_module(QuickControls2Impl
Qt::Core
Qt::Gui
Qt::Quick
- GENERATE_CPP_EXPORTS
)
qt_internal_extend_target(QuickControls2Impl CONDITION QT_FEATURE_quick_listview AND QT_FEATURE_quick_pathview
diff --git a/src/quickcontrolsimpl/qquickcolorimage.cpp b/src/quickcontrolsimpl/qquickcolorimage.cpp
index 5ad6d7d296..dcd87b5e72 100644
--- a/src/quickcontrolsimpl/qquickcolorimage.cpp
+++ b/src/quickcontrolsimpl/qquickcolorimage.cpp
@@ -57,12 +57,12 @@ void QQuickColorImage::pixmapChange()
QQuickImage::pixmapChange();
if (m_color.alpha() > 0 && m_color != m_defaultColor) {
QQuickImageBasePrivate *d = static_cast<QQuickImageBasePrivate *>(QQuickItemPrivate::get(this));
- QImage image = d->pix.image();
+ QImage image = d->currentPix->image();
if (!image.isNull()) {
QPainter painter(&image);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.fillRect(image.rect(), m_color);
- d->pix.setImage(image);
+ d->currentPix->setImage(image);
}
}
}
diff --git a/src/quickcontrolsimpl/qquickiconimage.cpp b/src/quickcontrolsimpl/qquickiconimage.cpp
index 24bb752ebd..c2af3e0539 100644
--- a/src/quickcontrolsimpl/qquickiconimage.cpp
+++ b/src/quickcontrolsimpl/qquickiconimage.cpp
@@ -82,7 +82,7 @@ void QQuickIconImagePrivate::updateFillMode()
updatingFillMode = true;
- const QSize pixmapSize = QSize(pix.width(), pix.height()) / calculateDevicePixelRatio();
+ const QSize pixmapSize = QSize(currentPix->width(), currentPix->height()) / calculateDevicePixelRatio();
if (pixmapSize.width() > q->width() || pixmapSize.height() > q->height())
q->setFillMode(QQuickImage::PreserveAspectFit);
else
@@ -186,12 +186,12 @@ void QQuickIconImage::pixmapChange()
// Don't apply the color if we're recursing (updateFillMode() can cause us to recurse).
if (!d->updatingFillMode && d->color.alpha() > 0) {
- QImage image = d->pix.image();
+ QImage image = d->currentPix->image();
if (!image.isNull()) {
QPainter painter(&image);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.fillRect(image.rect(), d->color);
- d->pix.setImage(image);
+ d->currentPix->setImage(image);
}
}
}
diff --git a/src/quickcontrolsimpl/qquickimageselector.cpp b/src/quickcontrolsimpl/qquickimageselector.cpp
index 35f6555684..3896c1cf3c 100644
--- a/src/quickcontrolsimpl/qquickimageselector.cpp
+++ b/src/quickcontrolsimpl/qquickimageselector.cpp
@@ -14,7 +14,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQtQuickControlsImageSelector, "qt.quick.controls.imageselector")
+Q_STATIC_LOGGING_CATEGORY(lcQtQuickControlsImageSelector, "qt.quick.controls.imageselector")
static const int DEFAULT_CACHE = 500;
diff --git a/src/quickcontrolsimpl/qquickninepatchimage.cpp b/src/quickcontrolsimpl/qquickninepatchimage.cpp
index d6238d2ccd..4d34123014 100644
--- a/src/quickcontrolsimpl/qquickninepatchimage.cpp
+++ b/src/quickcontrolsimpl/qquickninepatchimage.cpp
@@ -399,13 +399,13 @@ void QQuickNinePatchImage::pixmapChange()
if (!d->resetNode)
d->resetNode = d->ninePatch.isNull();
- d->ninePatch = d->pix.image();
+ d->ninePatch = d->currentPix->image();
if (d->ninePatch.depth() != 32)
d->ninePatch = std::move(d->ninePatch).convertToFormat(QImage::Format_ARGB32);
int w = d->ninePatch.width();
int h = d->ninePatch.height();
- d->pix.setImage(QImage(d->ninePatch.constBits() + 4 * (w + 1), w - 2, h - 2, d->ninePatch.bytesPerLine(), d->ninePatch.format()));
+ d->currentPix->setImage(QImage(d->ninePatch.constBits() + 4 * (w + 1), w - 2, h - 2, d->ninePatch.bytesPerLine(), d->ninePatch.format()));
d->updatePatches();
} else {
@@ -447,7 +447,7 @@ QSGNode *QQuickNinePatchImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNode
return QQuickImage::updatePaintNode(oldNode, data);
QSizeF sz = size();
- QImage image = d->pix.image();
+ QImage image = d->currentPix->image();
if (!sz.isValid() || image.isNull()) {
if (d->provider)
d->provider->updateTexture(nullptr);
diff --git a/src/quickcontrolsimpl/qquicktumblerview.cpp b/src/quickcontrolsimpl/qquicktumblerview.cpp
index 785791d117..021801bf23 100644
--- a/src/quickcontrolsimpl/qquicktumblerview.cpp
+++ b/src/quickcontrolsimpl/qquicktumblerview.cpp
@@ -13,7 +13,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcTumblerView, "qt.quick.controls.tumblerview")
+Q_STATIC_LOGGING_CATEGORY(lcTumblerView, "qt.quick.controls.tumblerview")
QQuickTumblerView::QQuickTumblerView(QQuickItem *parent) :
QQuickItem(parent)
diff --git a/src/quickdialogs/quickdialogs/CMakeLists.txt b/src/quickdialogs/quickdialogs/CMakeLists.txt
index ec9c37c2f9..893ee7cad8 100644
--- a/src/quickdialogs/quickdialogs/CMakeLists.txt
+++ b/src/quickdialogs/quickdialogs/CMakeLists.txt
@@ -45,11 +45,11 @@ qt_internal_add_qml_module(QuickDialogs2
Qt::QuickDialogs2UtilsPrivate
Qt::QuickDialogs2QuickImpl
Qt::QuickDialogs2QuickImplPrivate
+ Qt::QuickTemplates2Private
PUBLIC_LIBRARIES
Qt::Core
Qt::Gui
Qt::Quick
- GENERATE_CPP_EXPORTS
)
qt_internal_add_docs(QuickDialogs2
diff --git a/src/quickdialogs/quickdialogs/qquickabstractdialog.cpp b/src/quickdialogs/quickdialogs/qquickabstractdialog.cpp
index 1a77b86deb..5f5a56a233 100644
--- a/src/quickdialogs/quickdialogs/qquickabstractdialog.cpp
+++ b/src/quickdialogs/quickdialogs/qquickabstractdialog.cpp
@@ -103,8 +103,6 @@ Q_LOGGING_CATEGORY(lcDialogs, "qt.quick.dialogs")
\sa accepted()
*/
-Q_DECLARE_LOGGING_CATEGORY(lcDialogs)
-
QQuickAbstractDialog::QQuickAbstractDialog(QQuickDialogType type, QObject *parent)
: QObject(parent),
m_type(type)
diff --git a/src/quickdialogs/quickdialogs/qquickabstractdialog_p.h b/src/quickdialogs/quickdialogs/qquickabstractdialog_p.h
index 7926185447..6299b439c4 100644
--- a/src/quickdialogs/quickdialogs/qquickabstractdialog_p.h
+++ b/src/quickdialogs/quickdialogs/qquickabstractdialog_p.h
@@ -17,6 +17,7 @@
#include <memory>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qobject.h>
#include <QtGui/qpa/qplatformtheme.h>
#include <QtGui/qpa/qplatformdialoghelper.h>
@@ -29,6 +30,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcDialogs)
+
class QWindow;
class QPlatformDialogHelper;
diff --git a/src/quickdialogs/quickdialogs/qquickfiledialog.cpp b/src/quickdialogs/quickdialogs/qquickfiledialog.cpp
index 88b4047e40..5995f0c3f3 100644
--- a/src/quickdialogs/quickdialogs/qquickfiledialog.cpp
+++ b/src/quickdialogs/quickdialogs/qquickfiledialog.cpp
@@ -14,8 +14,7 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-Q_DECLARE_LOGGING_CATEGORY(lcDialogs)
-Q_LOGGING_CATEGORY(lcFileDialog, "qt.quick.dialogs.filedialog")
+Q_STATIC_LOGGING_CATEGORY(lcFileDialog, "qt.quick.dialogs.filedialog")
/*!
\qmltype FileDialog
diff --git a/src/quickdialogs/quickdialogs/qquickfolderdialog.cpp b/src/quickdialogs/quickdialogs/qquickfolderdialog.cpp
index db8885cc88..089c55570d 100644
--- a/src/quickdialogs/quickdialogs/qquickfolderdialog.cpp
+++ b/src/quickdialogs/quickdialogs/qquickfolderdialog.cpp
@@ -8,8 +8,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcDialogs)
-
/*!
\qmltype FolderDialog
\inherits Dialog
diff --git a/src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt b/src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt
index 9191eaa379..5e219624bc 100644
--- a/src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt
+++ b/src/quickdialogs/quickdialogsquickimpl/CMakeLists.txt
@@ -111,7 +111,6 @@ qt_internal_add_qml_module(QuickDialogs2QuickImpl
Qt::Core
Qt::Gui
Qt::Quick
- GENERATE_CPP_EXPORTS
)
add_dependencies(QuickDialogs2QuickImpl Qt::QuickControls2Basic)
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl.cpp b/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl.cpp
index 687e899d18..57d81c30a7 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl.cpp
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickfiledialogimpl.cpp
@@ -20,13 +20,13 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcCurrentFolder, "qt.quick.dialogs.quickfiledialogimpl.currentFolder")
-Q_LOGGING_CATEGORY(lcSelectedFile, "qt.quick.dialogs.quickfiledialogimpl.selectedFile")
-Q_LOGGING_CATEGORY(lcUpdateSelectedFile, "qt.quick.dialogs.quickfiledialogimpl.updateSelectedFile")
-Q_LOGGING_CATEGORY(lcOptions, "qt.quick.dialogs.quickfiledialogimpl.options")
-Q_LOGGING_CATEGORY(lcNameFilters, "qt.quick.dialogs.quickfiledialogimpl.namefilters")
-Q_LOGGING_CATEGORY(lcAttachedNameFilters, "qt.quick.dialogs.quickfiledialogimplattached.namefilters")
-Q_LOGGING_CATEGORY(lcAttachedCurrentIndex, "qt.quick.dialogs.quickfiledialogimplattached.currentIndex")
+Q_STATIC_LOGGING_CATEGORY(lcCurrentFolder, "qt.quick.dialogs.quickfiledialogimpl.currentFolder")
+Q_STATIC_LOGGING_CATEGORY(lcSelectedFile, "qt.quick.dialogs.quickfiledialogimpl.selectedFile")
+Q_STATIC_LOGGING_CATEGORY(lcUpdateSelectedFile, "qt.quick.dialogs.quickfiledialogimpl.updateSelectedFile")
+Q_STATIC_LOGGING_CATEGORY(lcOptions, "qt.quick.dialogs.quickfiledialogimpl.options")
+Q_STATIC_LOGGING_CATEGORY(lcNameFilters, "qt.quick.dialogs.quickfiledialogimpl.namefilters")
+Q_STATIC_LOGGING_CATEGORY(lcAttachedNameFilters, "qt.quick.dialogs.quickfiledialogimplattached.namefilters")
+Q_STATIC_LOGGING_CATEGORY(lcAttachedCurrentIndex, "qt.quick.dialogs.quickfiledialogimplattached.currentIndex")
QQuickFileDialogImplPrivate::QQuickFileDialogImplPrivate()
{
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickfolderbreadcrumbbar.cpp b/src/quickdialogs/quickdialogsquickimpl/qquickfolderbreadcrumbbar.cpp
index baa75b714c..fdb547134b 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickfolderbreadcrumbbar.cpp
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickfolderbreadcrumbbar.cpp
@@ -23,12 +23,12 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcFolderBreadcrumbBar, "qt.quick.dialogs.folderbreadcrumbbar")
-Q_LOGGING_CATEGORY(lcContentSize, "qt.quick.dialogs.folderbreadcrumbbar.contentsize")
-Q_LOGGING_CATEGORY(lcDelegates, "qt.quick.dialogs.folderbreadcrumbbar.delegates")
-Q_LOGGING_CATEGORY(lcShortcuts, "qt.quick.dialogs.folderbreadcrumbbar.shortcuts")
-Q_LOGGING_CATEGORY(lcTextInput, "qt.quick.dialogs.folderbreadcrumbbar.textinput")
-Q_LOGGING_CATEGORY(lcCurrentItem, "qt.quick.dialogs.folderbreadcrumbbar.currentitem")
+Q_STATIC_LOGGING_CATEGORY(lcFolderBreadcrumbBar, "qt.quick.dialogs.folderbreadcrumbbar")
+Q_STATIC_LOGGING_CATEGORY(lcContentSize, "qt.quick.dialogs.folderbreadcrumbbar.contentsize")
+Q_STATIC_LOGGING_CATEGORY(lcDelegates, "qt.quick.dialogs.folderbreadcrumbbar.delegates")
+Q_STATIC_LOGGING_CATEGORY(lcShortcuts, "qt.quick.dialogs.folderbreadcrumbbar.shortcuts")
+Q_STATIC_LOGGING_CATEGORY(lcTextInput, "qt.quick.dialogs.folderbreadcrumbbar.textinput")
+Q_STATIC_LOGGING_CATEGORY(lcCurrentItem, "qt.quick.dialogs.folderbreadcrumbbar.currentitem")
QQuickItem *QQuickFolderBreadcrumbBarPrivate::createDelegateItem(QQmlComponent *component, const QVariantMap &initialProperties)
{
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickfolderdialogimpl.cpp b/src/quickdialogs/quickdialogsquickimpl/qquickfolderdialogimpl.cpp
index 25d82a17aa..6b0afb4e58 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickfolderdialogimpl.cpp
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickfolderdialogimpl.cpp
@@ -12,9 +12,9 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcFolderDialogCurrentFolder, "qt.quick.dialogs.quickfolderdialogimpl.currentFolder")
-Q_LOGGING_CATEGORY(lcFolderDialogSelectedFolder, "qt.quick.dialogs.quickfolderdialogimpl.selectedFolder")
-Q_LOGGING_CATEGORY(lcFolderDialogOptions, "qt.quick.dialogs.quickfolderdialogimpl.options")
+Q_STATIC_LOGGING_CATEGORY(lcFolderDialogCurrentFolder, "qt.quick.dialogs.quickfolderdialogimpl.currentFolder")
+Q_STATIC_LOGGING_CATEGORY(lcFolderDialogSelectedFolder, "qt.quick.dialogs.quickfolderdialogimpl.selectedFolder")
+Q_STATIC_LOGGING_CATEGORY(lcFolderDialogOptions, "qt.quick.dialogs.quickfolderdialogimpl.options")
QQuickFolderDialogImplPrivate::QQuickFolderDialogImplPrivate()
{
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickfontdialogimpl.cpp b/src/quickdialogs/quickdialogsquickimpl/qquickfontdialogimpl.cpp
index 5dcde5a81e..e83913a738 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickfontdialogimpl.cpp
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickfontdialogimpl.cpp
@@ -11,7 +11,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcAttachedProperty, "qt.quick.dialogs.quickfontdialogimpl.attachedOrWarn")
+Q_STATIC_LOGGING_CATEGORY(lcAttachedProperty, "qt.quick.dialogs.quickfontdialogimpl.attachedOrWarn")
QQuickFontDialogImplPrivate::QQuickFontDialogImplPrivate()
{
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickplatformcolordialog.cpp b/src/quickdialogs/quickdialogsquickimpl/qquickplatformcolordialog.cpp
index 205b4e0b1b..1bc5018946 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickplatformcolordialog.cpp
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickplatformcolordialog.cpp
@@ -16,7 +16,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQuickPlatformColorDialog, "qt.quick.dialogs.quickplatformcolordialog")
+Q_STATIC_LOGGING_CATEGORY(lcQuickPlatformColorDialog, "qt.quick.dialogs.quickplatformcolordialog")
QQuickPlatformColorDialog::QQuickPlatformColorDialog(QObject *parent)
{
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickplatformfiledialog.cpp b/src/quickdialogs/quickdialogsquickimpl/qquickplatformfiledialog.cpp
index 1c9174a8e4..6f04afca54 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickplatformfiledialog.cpp
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickplatformfiledialog.cpp
@@ -17,7 +17,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQuickPlatformFileDialog, "qt.quick.dialogs.quickplatformfiledialog")
+Q_STATIC_LOGGING_CATEGORY(lcQuickPlatformFileDialog, "qt.quick.dialogs.quickplatformfiledialog")
/*!
\class QQuickPlatformFileDialog
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickplatformfolderdialog.cpp b/src/quickdialogs/quickdialogsquickimpl/qquickplatformfolderdialog.cpp
index d0ccea353e..699ee41999 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickplatformfolderdialog.cpp
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickplatformfolderdialog.cpp
@@ -16,7 +16,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQuickPlatformFolderDialog, "qt.quick.dialogs.quickplatformfolderdialog")
+Q_STATIC_LOGGING_CATEGORY(lcQuickPlatformFolderDialog, "qt.quick.dialogs.quickplatformfolderdialog")
/*!
\class QQuickPlatformFolderDialog
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickplatformfontdialog.cpp b/src/quickdialogs/quickdialogsquickimpl/qquickplatformfontdialog.cpp
index 4ef0b1bec6..1f9d599fe0 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickplatformfontdialog.cpp
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickplatformfontdialog.cpp
@@ -16,7 +16,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQuickPlatformFontDialog, "qt.quick.dialogs.quickplatformfontdialog")
+Q_STATIC_LOGGING_CATEGORY(lcQuickPlatformFontDialog, "qt.quick.dialogs.quickplatformfontdialog")
/*!
\class QQuickPlatformFontDialog
diff --git a/src/quickdialogs/quickdialogsquickimpl/qquickplatformmessagedialog.cpp b/src/quickdialogs/quickdialogsquickimpl/qquickplatformmessagedialog.cpp
index a9f1e858ed..08c96faab4 100644
--- a/src/quickdialogs/quickdialogsquickimpl/qquickplatformmessagedialog.cpp
+++ b/src/quickdialogs/quickdialogsquickimpl/qquickplatformmessagedialog.cpp
@@ -10,7 +10,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQuickPlatformMessageDialog, "qt.quick.dialogs.quickplatformmessagedialog")
+Q_STATIC_LOGGING_CATEGORY(lcQuickPlatformMessageDialog, "qt.quick.dialogs.quickplatformmessagedialog")
QQuickPlatformMessageDialog::QQuickPlatformMessageDialog(QObject *parent)
{
diff --git a/src/quickdialogs/quickdialogsutils/CMakeLists.txt b/src/quickdialogs/quickdialogsutils/CMakeLists.txt
index bcf54b279c..7254a98e44 100644
--- a/src/quickdialogs/quickdialogsutils/CMakeLists.txt
+++ b/src/quickdialogs/quickdialogsutils/CMakeLists.txt
@@ -24,5 +24,4 @@ qt_internal_add_module(QuickDialogs2Utils
Qt::GuiPrivate
PUBLIC_LIBRARIES
Qt::Core
- GENERATE_CPP_EXPORTS
)
diff --git a/src/quickdialogs/quickdialogsutils/qquickfilenamefilter.cpp b/src/quickdialogs/quickdialogsutils/qquickfilenamefilter.cpp
index 537ca1f058..820b78e517 100644
--- a/src/quickdialogs/quickdialogsutils/qquickfilenamefilter.cpp
+++ b/src/quickdialogs/quickdialogsutils/qquickfilenamefilter.cpp
@@ -7,7 +7,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcFileNameFilter, "qt.quick.dialogs.qquickfilenamefilter")
+Q_STATIC_LOGGING_CATEGORY(lcFileNameFilter, "qt.quick.dialogs.qquickfilenamefilter")
QQuickFileNameFilter::QQuickFileNameFilter(QObject *parent)
: QObject(parent), m_index(-1)
diff --git a/src/quicklayouts/CMakeLists.txt b/src/quicklayouts/CMakeLists.txt
index 4eeb697461..7dad1a0c33 100644
--- a/src/quicklayouts/CMakeLists.txt
+++ b/src/quicklayouts/CMakeLists.txt
@@ -24,5 +24,4 @@ qt_internal_add_qml_module(QuickLayouts
Qt::GuiPrivate
Qt::QuickPrivate
Qt::Qml
- GENERATE_CPP_EXPORTS
)
diff --git a/src/quicklayouts/qquicklayout.cpp b/src/quicklayouts/qquicklayout.cpp
index f38bdfd396..97da0a61c9 100644
--- a/src/quicklayouts/qquicklayout.cpp
+++ b/src/quicklayouts/qquicklayout.cpp
@@ -80,6 +80,8 @@ QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent)
m_fillHeight(false),
m_isFillWidthSet(false),
m_isFillHeightSet(false),
+ m_isUseDefaultSizePolicySet(false),
+ m_useDefaultSizePolicy(QQuickLayout::SizePolicyExplicit),
m_isMinimumWidthSet(false),
m_isMinimumHeightSet(false),
m_isMaximumWidthSet(false),
@@ -340,6 +342,30 @@ void QQuickLayoutAttached::setFillHeight(bool fill)
}
/*!
+ \qmlattachedproperty enumeration Layout::useDefaultSizePolicy
+ \since 6.8
+
+ This property allows the user to configure the layout size policy at the component
+ level.
+
+ The default value will be inherited by querying the application attribute
+ \l Qt::AA_QtQuickUseDefaultSizePolicy. You can use this property to override that value.
+
+ \value Layout.SizePolicyImplicit
+ The item in the layout uses implicit or built-in size policy
+ \value Layout.SizePolicyExplicit
+ The item in the layout don't use implicit size policies.
+*/
+void QQuickLayoutAttached::setUseDefaultSizePolicy(QQuickLayout::SizePolicy sizePolicy)
+{
+ m_isUseDefaultSizePolicySet = true;
+ if (m_useDefaultSizePolicy != sizePolicy) {
+ m_useDefaultSizePolicy = sizePolicy;
+ emit useDefaultSizePolicyChanged();
+ }
+}
+
+/*!
\qmlattachedproperty int Layout::row
This property allows you to specify the row position of an item in a \l GridLayout.
@@ -923,7 +949,8 @@ void QQuickLayout::geometryChange(const QRectF &newGeometry, const QRectF &oldGe
{
Q_D(QQuickLayout);
QQuickItem::geometryChange(newGeometry, oldGeometry);
- if (invalidated() || d->m_disableRearrange || !isReady())
+ if ((invalidated() && !qobject_cast<QQuickLayout *>(parentItem())) ||
+ d->m_disableRearrange || !isReady())
return;
qCDebug(lcQuickLayouts) << "QQuickLayout::geometryChange" << newGeometry << oldGeometry;
@@ -1253,29 +1280,33 @@ void QQuickLayout::effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSiz
*/
QLayoutPolicy::Policy QQuickLayout::effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info)
{
- bool fillExtent([&]{
- QLayoutPolicy::Policy policy{QLayoutPolicy::Fixed};
- if (item && QGuiApplication::testAttribute(Qt::AA_QtQuickUseDefaultSizePolicy)) {
- QLayoutPolicy sizePolicy = QQuickItemPrivate::get(item)->sizePolicy();
- policy = (orientation == Qt::Horizontal) ? sizePolicy.horizontalPolicy() : sizePolicy.verticalPolicy();
- }
- return (policy == QLayoutPolicy::Preferred);
- }());
-
+ QLayoutPolicy::Policy pol{QLayoutPolicy::Fixed};
bool isSet = false;
if (info) {
if (orientation == Qt::Horizontal) {
isSet = info->isFillWidthSet();
- if (isSet) fillExtent = info->fillWidth();
+ if (isSet && info->fillWidth())
+ pol = QLayoutPolicy::Preferred;
} else {
isSet = info->isFillHeightSet();
- if (isSet) fillExtent = info->fillHeight();
+ if (isSet && info->fillHeight())
+ pol = QLayoutPolicy::Preferred;
+ }
+ }
+ if (!isSet && item) {
+ auto effectiveUseDefaultSizePolicy = [info]() {
+ return info ? info->useDefaultSizePolicy() == QQuickLayout::SizePolicyImplicit
+ : QGuiApplication::testAttribute(Qt::AA_QtQuickUseDefaultSizePolicy);
+ };
+ if (qobject_cast<QQuickLayout*>(item)) {
+ pol = QLayoutPolicy::Preferred;
+ } else if (effectiveUseDefaultSizePolicy()) {
+ QLayoutPolicy sizePolicy = QQuickItemPrivate::get(item)->sizePolicy();
+ pol = (orientation == Qt::Horizontal) ? sizePolicy.horizontalPolicy() : sizePolicy.verticalPolicy();
}
}
- if (!isSet && qobject_cast<QQuickLayout*>(item))
- fillExtent = true;
- return fillExtent ? QLayoutPolicy::Preferred : QLayoutPolicy::Fixed;
+ return pol;
}
void QQuickLayout::_q_dumpLayoutTree() const
diff --git a/src/quicklayouts/qquicklayout_p.h b/src/quicklayouts/qquicklayout_p.h
index f0ccc6dbf5..2f29c783d5 100644
--- a/src/quicklayouts/qquicklayout_p.h
+++ b/src/quicklayouts/qquicklayout_p.h
@@ -53,6 +53,12 @@ public:
ApplySizeHints = 0b010
};
+ enum SizePolicy {
+ SizePolicyImplicit = 1,
+ SizePolicyExplicit
+ };
+ Q_ENUM(SizePolicy)
+
Q_DECLARE_FLAGS(EnsureLayoutItemsUpdatedOptions, EnsureLayoutItemsUpdatedOption)
explicit QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent = nullptr);
@@ -168,6 +174,7 @@ class Q_QUICKLAYOUTS_EXPORT QQuickLayoutAttached : public QObject
Q_PROPERTY(qreal maximumHeight READ maximumHeight WRITE setMaximumHeight NOTIFY maximumHeightChanged FINAL)
Q_PROPERTY(bool fillHeight READ fillHeight WRITE setFillHeight NOTIFY fillHeightChanged FINAL)
Q_PROPERTY(bool fillWidth READ fillWidth WRITE setFillWidth NOTIFY fillWidthChanged FINAL)
+ Q_PROPERTY(QQuickLayout::SizePolicy useDefaultSizePolicy READ useDefaultSizePolicy WRITE setUseDefaultSizePolicy NOTIFY useDefaultSizePolicyChanged FINAL)
Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged FINAL)
Q_PROPERTY(int column READ column WRITE setColumn NOTIFY columnChanged FINAL)
Q_PROPERTY(int rowSpan READ rowSpan WRITE setRowSpan NOTIFY rowSpanChanged FINAL)
@@ -213,21 +220,31 @@ public:
void setMaximumImplicitSize(const QSizeF &sz);
bool fillWidth() const {
- if (auto *itemPriv = itemForSizePolicy(m_isFillWidthSet))
- return (itemPriv->sizePolicy().horizontalPolicy() == QLayoutPolicy::Preferred);
+ if (auto *itemPriv = itemForSizePolicy(m_isFillWidthSet)) {
+ QLayoutPolicy::Policy hPolicy = itemPriv->sizePolicy().horizontalPolicy();
+ return hPolicy & QLayoutPolicy::GrowFlag;
+ }
return m_fillWidth;
}
void setFillWidth(bool fill);
bool isFillWidthSet() const { return m_isFillWidthSet; }
bool fillHeight() const {
- if (auto *itemPriv = itemForSizePolicy(m_isFillHeightSet))
- return (itemPriv->sizePolicy().verticalPolicy() == QLayoutPolicy::Preferred);
+ if (auto *itemPriv = itemForSizePolicy(m_isFillHeightSet)) {
+ QLayoutPolicy::Policy vPolicy = itemPriv->sizePolicy().verticalPolicy();
+ return vPolicy & QLayoutPolicy::GrowFlag;
+ }
return m_fillHeight;
}
void setFillHeight(bool fill);
bool isFillHeightSet() const { return m_isFillHeightSet; }
+ QQuickLayout::SizePolicy useDefaultSizePolicy() const {
+ const bool appDefSizePolicy = QGuiApplication::testAttribute(Qt::AA_QtQuickUseDefaultSizePolicy);
+ return (m_isUseDefaultSizePolicySet ? m_useDefaultSizePolicy : (appDefSizePolicy ? QQuickLayout::SizePolicyImplicit : QQuickLayout::SizePolicyExplicit));
+ }
+ void setUseDefaultSizePolicy(QQuickLayout::SizePolicy sizePolicy);
+
int row() const { return qMax(m_row, 0); }
void setRow(int row);
bool isRowSet() const { return m_row >= 0; }
@@ -330,6 +347,7 @@ Q_SIGNALS:
void maximumHeightChanged();
void fillWidthChanged();
void fillHeightChanged();
+ void useDefaultSizePolicyChanged();
void leftMarginChanged();
void topMarginChanged();
void rightMarginChanged();
@@ -371,6 +389,8 @@ private:
unsigned m_fillHeight : 1;
unsigned m_isFillWidthSet : 1;
unsigned m_isFillHeightSet : 1;
+ unsigned m_isUseDefaultSizePolicySet: 1;
+ QQuickLayout::SizePolicy m_useDefaultSizePolicy;
unsigned m_isMinimumWidthSet : 1;
unsigned m_isMinimumHeightSet : 1;
// preferredWidth and preferredHeight are always explicit, since
diff --git a/src/quicklayouts/qquicklayoutitemproxy.cpp b/src/quicklayouts/qquicklayoutitemproxy.cpp
index f690a2eae8..84602d7f69 100644
--- a/src/quicklayouts/qquicklayoutitemproxy.cpp
+++ b/src/quicklayouts/qquicklayoutitemproxy.cpp
@@ -73,7 +73,7 @@
\sa Item, GridLayout, RowLayout, ColumnLayout
*/
-Q_LOGGING_CATEGORY(lcLayouts, "qt.quick.layouts")
+Q_STATIC_LOGGING_CATEGORY(lcLayouts, "qt.quick.layouts")
QQuickLayoutItemProxy::QQuickLayoutItemProxy(QQuickItem *parent)
diff --git a/src/quicknativestyle/controls/DefaultSpinBox.qml b/src/quicknativestyle/controls/DefaultSpinBox.qml
index beb49d98a2..889ca4f326 100644
--- a/src/quicknativestyle/controls/DefaultSpinBox.qml
+++ b/src/quicknativestyle/controls/DefaultSpinBox.qml
@@ -33,7 +33,6 @@ T.SpinBox {
contentItem: TextInput {
text: control.displayText
- font: font.font
color: control.palette.text
selectionColor: control.palette.highlight
selectedTextColor: control.palette.highlightedText
diff --git a/src/quicknativestyle/qstyle/qquickcommonstyle.cpp b/src/quicknativestyle/qstyle/qquickcommonstyle.cpp
index 530dc24f84..02bd1a694c 100644
--- a/src/quicknativestyle/qstyle/qquickcommonstyle.cpp
+++ b/src/quicknativestyle/qstyle/qquickcommonstyle.cpp
@@ -4443,7 +4443,7 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt) const
ret = int(QStyleHelper::dpiScaled(13, opt));
break;
case PM_MessageBoxIconSize:
-#ifdef Q_OS_MAC
+#ifdef Q_OS_APPLE
if (QGuiApplication::desktopSettingsAware()) {
ret = 64; // No DPI scaling, it's handled elsewhere.
} else
@@ -5662,7 +5662,7 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption
if (!icon.isNull())
return icon;
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_MACOS)
if (QGuiApplication::desktopSettingsAware()) {
switch (standardIcon) {
case SP_DirIcon: {
@@ -5730,7 +5730,7 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption
break;
}
} // if (QGuiApplication::desktopSettingsAware())
-#endif // Q_OS_MAC
+#endif // Q_OS_MACOS
switch (standardIcon) {
#ifndef QT_NO_IMAGEFORMAT_PNG
diff --git a/src/quickshapes/CMakeLists.txt b/src/quickshapes/CMakeLists.txt
index 7b52826751..78297fb532 100644
--- a/src/quickshapes/CMakeLists.txt
+++ b/src/quickshapes/CMakeLists.txt
@@ -27,7 +27,6 @@ qt_internal_add_qml_module(QuickShapesPrivate
Qt::GuiPrivate
Qt::Qml
Qt::QuickPrivate
- GENERATE_CPP_EXPORTS
)
# We need to do additional initialization, so we have to provide our own
@@ -52,6 +51,8 @@ qt_internal_add_shaders(QuickShapesPrivate "qtquickshapes_shaders"
"shaders_ng/radialgradient.frag"
"shaders_ng/conicalgradient.vert"
"shaders_ng/conicalgradient.frag"
+ "shaders_ng/texturefill.vert"
+ "shaders_ng/texturefill.frag"
"shaders_ng/wireframe.frag"
"shaders_ng/wireframe.vert"
)
diff --git a/src/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp
index 96f83b9af6..88a4fe7d3f 100644
--- a/src/quickshapes/qquickshape.cpp
+++ b/src/quickshapes/qquickshape.cpp
@@ -22,7 +22,7 @@ static void initResources()
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(QQSHAPE_LOG_TIME_DIRTY_SYNC, "qt.shape.time.sync")
+Q_STATIC_LOGGING_CATEGORY(QQSHAPE_LOG_TIME_DIRTY_SYNC, "qt.shape.time.sync")
/*!
\qmlmodule QtQuick.Shapes 1.\QtMinorVersion
@@ -88,7 +88,8 @@ QQuickShapeStrokeFillParams::QQuickShapeStrokeFillParams()
capStyle(QQuickShapePath::SquareCap),
strokeStyle(QQuickShapePath::SolidLine),
dashOffset(0),
- fillGradient(nullptr)
+ fillGradient(nullptr),
+ fillItem(nullptr)
{
dashPattern << 4 << 2; // 4 * strokeWidth dash followed by 2 * strokeWidth space
}
@@ -240,6 +241,9 @@ void QQuickShapePath::setStrokeWidth(qreal w)
When set to \c transparent, no filling occurs.
The default value is \c white.
+
+ \note If either \l fillGradient or \l fillItem are set to something other than \c null, these
+ will take precedence over \c fillColor. The \c fillColor will be ignored in this case.
*/
QColor QQuickShapePath::fillColor() const
@@ -474,14 +478,14 @@ void QQuickShapePath::setDashPattern(const QVector<qreal> &array)
\qmlproperty ShapeGradient QtQuick.Shapes::ShapePath::fillGradient
This property defines the fill gradient. By default no gradient is enabled
- and the value is \c null. In this case the fill uses a solid color based
- on the value of ShapePath.fillColor.
-
- When set, ShapePath.fillColor is ignored and filling is done using one of
- the ShapeGradient subtypes.
+ and the value is \c null. In this case the fill will either be based on the \l fillItem
+ property if it is set, and otherwise the \l{fillColor} property will be used.
\note The Gradient type cannot be used here. Rather, prefer using one of
the advanced subtypes, like LinearGradient.
+
+ \note If set to something other than \c{null}, the \c fillGradient will take precedence over
+ both \l fillItem and \l fillColor.
*/
QQuickShapeGradient *QQuickShapePath::fillGradient() const
@@ -506,6 +510,11 @@ void QQuickShapePath::setFillGradient(QQuickShapeGradient *gradient)
}
}
+void QQuickShapePath::resetFillGradient()
+{
+ setFillGradient(nullptr);
+}
+
void QQuickShapePathPrivate::_q_fillGradientChanged()
{
Q_Q(QQuickShapePath);
@@ -513,9 +522,58 @@ void QQuickShapePathPrivate::_q_fillGradientChanged()
emit q->shapePathChanged();
}
-void QQuickShapePath::resetFillGradient()
+/*!
+ \qmlproperty Item QtQuick.Shapes::ShapePath::fillItem
+ \since 6.8
+
+ This property defines another Qt Quick Item to use as fill by the shape. The item must be
+ texture provider (such as a \l {Item Layers} {layered item}, a \l{ShaderEffectSource} or an
+ \l{Image}). If it is not a valid texture provider, this property will be ignored.
+
+ \note When using a layered item as a \c fillItem, you may see pixelation effects when
+ transforming the fill. Setting the \l layer.smooth property to true will give better visual
+ results in this case.
+
+ By default no fill item is set and the value is \c null.
+
+ \note If set to something other than \c null, the \c fillItem property takes precedence over
+ \l fillColor. The \l fillGradient property in turn takes precedence over both \c fillItem and
+ \l{fillColor}.
+ */
+
+QQuickItem *QQuickShapePath::fillItem() const
{
- setFillGradient(nullptr);
+ Q_D(const QQuickShapePath);
+ return d->sfp.fillItem;
+}
+
+void QQuickShapePath::setFillItem(QQuickItem *fillItem)
+{
+ Q_D(QQuickShapePath);
+ if (d->sfp.fillItem != fillItem) {
+ if (d->sfp.fillItem != nullptr) {
+ qmlobject_disconnect(d->sfp.fillItem, QQuickItem, SIGNAL(destroyed()),
+ this, QQuickShapePath, SLOT(_q_fillItemDestroyed()));
+ }
+ d->sfp.fillItem = fillItem;
+ if (d->sfp.fillItem != nullptr) {
+ qmlobject_connect(d->sfp.fillItem, QQuickItem, SIGNAL(destroyed()),
+ this, QQuickShapePath, SLOT(_q_fillItemDestroyed()));
+ }
+ emit fillItemChanged();
+
+ d->dirty |= QQuickShapePathPrivate::DirtyFillItem;
+ emit shapePathChanged();
+ }
+}
+
+void QQuickShapePathPrivate::_q_fillItemDestroyed()
+{
+ Q_Q(QQuickShapePath);
+ sfp.fillItem = nullptr;
+ dirty |= DirtyFillItem;
+ emit q->fillItemChanged();
+ emit q->shapePathChanged();
}
/*!
@@ -547,8 +605,8 @@ void QQuickShapePath::resetFillGradient()
This implies \c PathNonIntersecting.
Not all hints are logically independent, but the dependencies are not enforced.
- For example, \c PathIsLinear implies \c PathIsQuadratic, but it is valid to have \c PathIsLinear
- without \c PathIsQuadratic.
+ For example, \c PathLinear implies \c PathQuadratic, but it is valid to have \c PathLinear
+ without \c PathQuadratic.
The pathHints property describes a set of statements known to be true; the absence of a hint
does not necessarily mean that the corresponding statement is false.
@@ -570,6 +628,32 @@ void QQuickShapePath::setPathHints(PathHints newPathHints)
}
/*!
+ \qmlproperty matrix4x4 QtQuick.Shapes::ShapePath::fillTransform
+ \since 6.8
+
+ This property defines a transform to be applied to the path's fill pattern (gradient). It has
+ no effect if the fill is a solid color or transparent. By default no fill transform is enabled
+ and the value of this property is the \c identity matrix.
+*/
+
+QMatrix4x4 QQuickShapePath::fillTransform() const
+{
+ Q_D(const QQuickShapePath);
+ return d->sfp.fillTransform.matrix();
+}
+
+void QQuickShapePath::setFillTransform(const QMatrix4x4 &matrix)
+{
+ Q_D(QQuickShapePath);
+ if (d->sfp.fillTransform != matrix) {
+ d->sfp.fillTransform.setMatrix(matrix);
+ d->dirty |= QQuickShapePathPrivate::DirtyFillTransform;
+ emit fillTransformChanged();
+ emit shapePathChanged();
+ }
+}
+
+/*!
\qmltype Shape
//! \instantiates QQuickShape
\inqmlmodule QtQuick.Shapes
@@ -700,6 +784,12 @@ void QQuickShapePrivate::_q_shapePathChanged()
q->setImplicitSize(br.right(), br.bottom());
}
+void QQuickShapePrivate::handleSceneChange(QQuickWindow *w)
+{
+ if (renderer != nullptr)
+ renderer->handleSceneChange(w);
+}
+
void QQuickShapePrivate::setStatus(QQuickShape::Status newStatus)
{
Q_Q(QQuickShape);
@@ -1164,6 +1254,7 @@ void QQuickShape::itemChange(ItemChange change, const ItemChangeData &data)
for (int i = 0; i < d->sp.size(); ++i)
QQuickShapePathPrivate::get(d->sp[i])->dirty = QQuickShapePathPrivate::DirtyAll;
d->_q_shapePathChanged();
+ d->handleSceneChange(data.window);
}
QQuickItem::itemChange(change, data);
@@ -1214,7 +1305,10 @@ QSGNode *QQuickShape::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
ty = (height() - h) / 2;
fillModeTransform.translate(tx / xScale, ty / yScale);
}
- static_cast<QSGTransformNode *>(node)->setMatrix(fillModeTransform);
+
+ QSGTransformNode *transformNode = static_cast<QSGTransformNode *>(node);
+ if (fillModeTransform != transformNode->matrix())
+ transformNode->setMatrix(fillModeTransform);
}
return node;
}
@@ -1368,6 +1462,18 @@ void QQuickShapePrivate::sync()
renderer->setStrokeStyle(i, p->strokeStyle(), p->dashOffset(), p->dashPattern());
if (dirty & QQuickShapePathPrivate::DirtyFillGradient)
renderer->setFillGradient(i, p->fillGradient());
+ if (dirty & QQuickShapePathPrivate::DirtyFillTransform)
+ renderer->setFillTransform(i, QQuickShapePathPrivate::get(p)->sfp.fillTransform);
+ if (dirty & QQuickShapePathPrivate::DirtyFillItem) {
+ if (p->fillItem() == nullptr) {
+ renderer->setFillTextureProvider(i, nullptr);
+ } else if (p->fillItem()->isTextureProvider()) {
+ renderer->setFillTextureProvider(i, p->fillItem());
+ } else {
+ renderer->setFillTextureProvider(i, nullptr);
+ qWarning() << "QQuickShape: Fill item is not texture provider";
+ }
+ }
dirty = 0;
}
diff --git a/src/quickshapes/qquickshape_p.h b/src/quickshapes/qquickshape_p.h
index effbce1f8e..3ed4927c2d 100644
--- a/src/quickshapes/qquickshape_p.h
+++ b/src/quickshapes/qquickshape_p.h
@@ -197,6 +197,8 @@ class Q_QUICKSHAPES_EXPORT QQuickShapePath : public QQuickPath
Q_PROPERTY(QQuickShapeGradient *fillGradient READ fillGradient WRITE setFillGradient RESET resetFillGradient)
Q_PROPERTY(QSizeF scale READ scale WRITE setScale NOTIFY scaleChanged REVISION(1, 14))
Q_PROPERTY(PathHints pathHints READ pathHints WRITE setPathHints NOTIFY pathHintsChanged REVISION(6, 7) FINAL)
+ Q_PROPERTY(QMatrix4x4 fillTransform READ fillTransform WRITE setFillTransform NOTIFY fillTransformChanged REVISION(6, 8) FINAL)
+ Q_PROPERTY(QQuickItem *fillItem READ fillItem WRITE setFillItem NOTIFY fillItemChanged REVISION(6, 8) FINAL)
QML_NAMED_ELEMENT(ShapePath)
QML_ADDED_IN_VERSION(1, 0)
@@ -279,6 +281,12 @@ public:
PathHints pathHints() const;
void setPathHints(PathHints newPathHints);
+ QMatrix4x4 fillTransform() const;
+ void setFillTransform(const QMatrix4x4 &matrix);
+
+ QQuickItem *fillItem() const;
+ void setFillItem(QQuickItem *newFillItem);
+
Q_SIGNALS:
void shapePathChanged();
void strokeColorChanged();
@@ -293,11 +301,14 @@ Q_SIGNALS:
void dashPatternChanged();
Q_REVISION(6, 7) void pathHintsChanged();
+ Q_REVISION(6, 8) void fillTransformChanged();
+ Q_REVISION(6, 8) void fillItemChanged();
private:
Q_DISABLE_COPY(QQuickShapePath)
Q_DECLARE_PRIVATE(QQuickShapePath)
Q_PRIVATE_SLOT(d_func(), void _q_fillGradientChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_fillItemDestroyed())
};
class Q_QUICKSHAPES_EXPORT QQuickShape : public QQuickItem
diff --git a/src/quickshapes/qquickshape_p_p.h b/src/quickshapes/qquickshape_p_p.h
index a36aa1e27f..cce52d876f 100644
--- a/src/quickshapes/qquickshape_p_p.h
+++ b/src/quickshapes/qquickshape_p_p.h
@@ -18,6 +18,7 @@
#include <QtQuickShapes/private/qquickshapesglobal_p.h>
#include <QtQuickShapes/private/qquickshape_p.h>
#include <private/qquickitem_p.h>
+#include <private/qsgtransform_p.h>
#include <QPainterPath>
#include <QColor>
#include <QBrush>
@@ -56,7 +57,10 @@ public:
virtual void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
qreal dashOffset, const QVector<qreal> &dashPattern) = 0;
virtual void setFillGradient(int index, QQuickShapeGradient *gradient) = 0;
+ virtual void setFillTextureProvider(int index, QQuickItem *textureProviderItem) = 0;
+ virtual void setFillTransform(int index, const QSGTransform &transform) = 0;
virtual void setTriangulationScale(qreal) { }
+ virtual void handleSceneChange(QQuickWindow *window) = 0;
// Render thread, with gui blocked
virtual void updateNode() = 0;
@@ -79,6 +83,8 @@ struct QQuickShapeStrokeFillParams
qreal dashOffset;
QVector<qreal> dashPattern;
QQuickShapeGradient *fillGradient;
+ QSGTransform fillTransform;
+ QQuickItem *fillItem;
};
class Q_QUICKSHAPES_EXPORT QQuickShapePathPrivate : public QQuickPathPrivate
@@ -95,14 +101,19 @@ public:
DirtyStyle = 0x20,
DirtyDash = 0x40,
DirtyFillGradient = 0x80,
+ DirtyFillTransform = 0x100,
+ DirtyFillItem = 0x200,
- DirtyAll = 0xFF
+ DirtyAll = 0x3FF
};
QQuickShapePathPrivate();
void _q_pathChanged();
void _q_fillGradientChanged();
+ void _q_fillItemDestroyed();
+
+ void handleSceneChange();
static QQuickShapePathPrivate *get(QQuickShapePath *p) { return p->d_func(); }
@@ -126,6 +137,7 @@ public:
void _q_shapePathChanged();
void setStatus(QQuickShape::Status newStatus);
+ void handleSceneChange(QQuickWindow *w);
static QQuickShapePrivate *get(QQuickShape *item) { return item->d_func(); }
diff --git a/src/quickshapes/qquickshapecurverenderer.cpp b/src/quickshapes/qquickshapecurverenderer.cpp
index 856d83fdac..6c16df449b 100644
--- a/src/quickshapes/qquickshapecurverenderer.cpp
+++ b/src/quickshapes/qquickshapecurverenderer.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquickshapecurverenderer_p.h"
@@ -233,6 +233,7 @@ void QQuickShapeCurveRenderer::setStrokeStyle(int index,
void QQuickShapeCurveRenderer::setFillGradient(int index, QQuickShapeGradient *gradient)
{
PathData &pd(m_paths[index]);
+ const bool wasVisible = pd.isFillVisible();
pd.gradientType = QGradient::NoGradient;
if (QQuickShapeLinearGradient *g = qobject_cast<QQuickShapeLinearGradient *>(gradient)) {
pd.gradientType = QGradient::LinearGradient;
@@ -250,8 +251,7 @@ void QQuickShapeCurveRenderer::setFillGradient(int index, QQuickShapeGradient *g
pd.gradientType = QGradient::ConicalGradient;
pd.gradient.a = QPointF(g->centerX(), g->centerY());
pd.gradient.v0 = g->angle();
- } else
- if (gradient != nullptr) {
+ } else if (gradient != nullptr) {
static bool warned = false;
if (!warned) {
warned = true;
@@ -264,7 +264,38 @@ void QQuickShapeCurveRenderer::setFillGradient(int index, QQuickShapeGradient *g
pd.gradient.spread = QGradient::Spread(gradient->spread());
}
- pd.m_dirty |= FillDirty;
+ pd.m_dirty |= (pd.isFillVisible() != wasVisible) ? FillDirty : UniformsDirty;
+}
+
+void QQuickShapeCurveRenderer::setFillTransform(int index, const QSGTransform &transform)
+{
+ auto &pathData = m_paths[index];
+ pathData.fillTransform = transform;
+ pathData.m_dirty |= UniformsDirty;
+}
+
+void QQuickShapeCurveRenderer::setFillTextureProvider(int index, QQuickItem *textureProviderItem)
+{
+ auto &pathData = m_paths[index];
+ const bool wasVisible = pathData.isFillVisible();
+ if (pathData.fillTextureProviderItem != nullptr)
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->derefWindow();
+ pathData.fillTextureProviderItem = textureProviderItem;
+ if (pathData.fillTextureProviderItem != nullptr)
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->refWindow(m_item->window());
+ pathData.m_dirty |= (pathData.isFillVisible() != wasVisible) ? FillDirty : UniformsDirty;
+}
+
+void QQuickShapeCurveRenderer::handleSceneChange(QQuickWindow *window)
+{
+ for (auto &pathData : m_paths) {
+ if (pathData.fillTextureProviderItem != nullptr) {
+ if (window == nullptr)
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->derefWindow();
+ else
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->refWindow(window);
+ }
+ }
}
void QQuickShapeCurveRenderer::setAsyncCallback(void (*callback)(void *), void *data)
@@ -357,8 +388,16 @@ void QQuickShapeCurveRenderer::updateNode()
return;
auto updateUniforms = [](const PathData &pathData) {
- for (auto &pathNode : std::as_const(pathData.fillNodes))
- pathNode->setColor(pathData.fillColor);
+ for (auto &pathNode : std::as_const(pathData.fillNodes)) {
+ QSGCurveFillNode *fillNode = static_cast<QSGCurveFillNode *>(pathNode);
+ fillNode->setColor(pathData.fillColor);
+ fillNode->setGradientType(pathData.gradientType);
+ fillNode->setFillGradient(pathData.gradient);
+ fillNode->setFillTransform(pathData.fillTransform);
+ fillNode->setFillTextureProvider(pathData.fillTextureProviderItem != nullptr
+ ? pathData.fillTextureProviderItem->textureProvider()
+ : nullptr);
+ }
for (auto &strokeNode : std::as_const(pathData.strokeNodes))
strokeNode->setColor(pathData.pen.color());
};
@@ -451,8 +490,8 @@ void QQuickShapeCurveRenderer::processPath(PathData *pathData)
if (doOverlapSolving)
QSGCurveProcessor::solveOverlaps(pathData->fillPath);
}
- pathData->fillNodes = addFillNodes(*pathData);
- dirtyFlags |= StrokeDirty;
+ pathData->fillNodes = addFillNodes(pathData->fillPath);
+ dirtyFlags |= (StrokeDirty | UniformsDirty);
}
}
@@ -472,17 +511,15 @@ void QQuickShapeCurveRenderer::processPath(PathData *pathData)
}
}
-QQuickShapeCurveRenderer::NodeList QQuickShapeCurveRenderer::addFillNodes(const PathData &pathData)
+QQuickShapeCurveRenderer::NodeList QQuickShapeCurveRenderer::addFillNodes(const QQuadPath &path)
{
auto *node = new QSGCurveFillNode;
- node->setGradientType(pathData.gradientType);
- const qsizetype approxDataCount = 20 * pathData.fillPath.elementCount();
+ const qsizetype approxDataCount = 20 * path.elementCount();
node->reserve(approxDataCount);
NodeList ret;
- const QColor &color = pathData.fillColor;
QPainterPath internalHull;
- internalHull.setFillRule(pathData.fillPath.fillRule());
+ internalHull.setFillRule(path.fillRule());
bool visualizeDebug = debugVisualization() & DebugCurves;
const float dbg = visualizeDebug ? 0.5f : 0.0f;
@@ -491,8 +528,8 @@ QQuickShapeCurveRenderer::NodeList QQuickShapeCurveRenderer::addFillNodes(const
QVector<QQuickShapeWireFrameNode::WireFrameVertex> wfVertices;
wfVertices.reserve(approxDataCount);
- QSGCurveProcessor::processFill(pathData.fillPath,
- pathData.fillRule,
+ QSGCurveProcessor::processFill(path,
+ path.fillRule(),
[&wfVertices, &node](const std::array<QVector2D, 3> &v,
const std::array<QVector2D, 3> &n,
QSGCurveProcessor::uvForPointCallback uvForPoint)
@@ -506,9 +543,6 @@ QQuickShapeCurveRenderer::NodeList QQuickShapeCurveRenderer::addFillNodes(const
QVector<quint32> indices = node->uncookedIndexes();
if (indices.size() > 0) {
- node->setColor(color);
- node->setFillGradient(pathData.gradient);
-
node->cookGeometry();
ret.append(node);
}
diff --git a/src/quickshapes/qquickshapecurverenderer_p.h b/src/quickshapes/qquickshapecurverenderer_p.h
index f2b10fb44c..a664b5efb4 100644
--- a/src/quickshapes/qquickshapecurverenderer_p.h
+++ b/src/quickshapes/qquickshapecurverenderer_p.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQUICKSHAPECURVERENDERER_P_H
@@ -55,9 +55,12 @@ public:
void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
qreal dashOffset, const QVector<qreal> &dashPattern) override;
void setFillGradient(int index, QQuickShapeGradient *gradient) override;
+ void setFillTextureProvider(int index, QQuickItem *textureProviderItem) override;
+ void setFillTransform(int index, const QSGTransform &transform) override;
void endSync(bool async) override;
void setAsyncCallback(void (*)(void *), void *) override;
Flags flags() const override { return SupportsAsync; }
+ void handleSceneChange(QQuickWindow *window) override;
void updateNode() override;
@@ -85,7 +88,12 @@ public:
private:
struct PathData {
- bool isFillVisible() const { return fillColor.alpha() > 0 || gradientType != QGradient::NoGradient; }
+ bool isFillVisible() const
+ {
+ return gradientType != QGradient::NoGradient
+ || fillTextureProviderItem != nullptr
+ || fillColor.alpha() > 0;
+ }
bool isStrokeVisible() const
{
@@ -94,6 +102,7 @@ private:
QGradient::Type gradientType = QGradient::NoGradient;
QSGGradientCache::GradientDesc gradient;
+ QSGTransform fillTransform;
QColor fillColor;
Qt::FillRule fillRule = Qt::OddEvenFill;
QPen pen;
@@ -110,13 +119,14 @@ private:
NodeList strokeNodes;
QQuickShapeCurveRunnable *currentRunner = nullptr;
+ QQuickItem *fillTextureProviderItem = nullptr;
};
void createRunner(PathData *pathData);
void maybeUpdateAsyncItem();
static void processPath(PathData *pathData);
- static NodeList addFillNodes(const PathData &pathData);
+ static NodeList addFillNodes(const QQuadPath &path);
static NodeList addTriangulatingStrokerNodes(const PathData &pathData);
static NodeList addCurveStrokeNodes(const PathData &pathData);
diff --git a/src/quickshapes/qquickshapegenericrenderer.cpp b/src/quickshapes/qquickshapegenericrenderer.cpp
index a18479f776..34c7fa96a0 100644
--- a/src/quickshapes/qquickshapegenericrenderer.cpp
+++ b/src/quickshapes/qquickshapegenericrenderer.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquickshapegenericrenderer_p.h"
@@ -6,6 +6,8 @@
#include <QtGui/private/qtriangulatingstroker_p.h>
#include <rhi/qrhi.h>
#include <QSGVertexColorMaterial>
+#include <QSGTextureProvider>
+#include <private/qsgplaintexture_p.h>
#include <QtQuick/private/qsggradientcache_p.h>
@@ -42,6 +44,7 @@ QQuickShapeGenericStrokeFillNode::QQuickShapeGenericStrokeFillNode(QQuickWindow
: m_material(nullptr)
{
setFlag(QSGNode::OwnsGeometry, true);
+ setFlag(QSGNode::UsePreprocess, true);
setGeometry(new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0, 0));
activateMaterial(window, MatSolidColor);
#ifdef QSG_RUNTIME_DESCRIPTION
@@ -66,6 +69,9 @@ void QQuickShapeGenericStrokeFillNode::activateMaterial(QQuickWindow *window, Ma
case MatConicalGradient:
m_material.reset(QQuickShapeGenericMaterialFactory::createConicalGradient(window, this));
break;
+ case MatTextureFill:
+ m_material.reset(QQuickShapeGenericMaterialFactory::createTextureFill(window, this));
+ break;
default:
qWarning("Unknown material %d", m);
return;
@@ -75,6 +81,25 @@ void QQuickShapeGenericStrokeFillNode::activateMaterial(QQuickWindow *window, Ma
setMaterial(m_material.data());
}
+void QQuickShapeGenericStrokeFillNode::preprocess()
+{
+ if (m_fillTextureProvider != nullptr) {
+ if (QSGDynamicTexture *texture = qobject_cast<QSGDynamicTexture *>(m_fillTextureProvider->texture()))
+ texture->updateTexture();
+ }
+}
+
+void QQuickShapeGenericStrokeFillNode::handleTextureChanged()
+{
+ markDirty(QSGNode::DirtyMaterial);
+}
+
+void QQuickShapeGenericStrokeFillNode::handleTextureProviderDestroyed()
+{
+ m_fillTextureProvider = nullptr;
+ markDirty(QSGNode::DirtyMaterial);
+}
+
QQuickShapeGenericRenderer::~QQuickShapeGenericRenderer()
{
for (ShapePathData &d : m_sp) {
@@ -202,6 +227,39 @@ void QQuickShapeGenericRenderer::setFillGradient(int index, QQuickShapeGradient
d.syncDirty |= DirtyFillGradient;
}
+void QQuickShapeGenericRenderer::setFillTextureProvider(int index, QQuickItem *textureProviderItem)
+{
+ ShapePathData &d(m_sp[index]);
+ if ((d.fillTextureProviderItem == nullptr) != (textureProviderItem == nullptr))
+ d.syncDirty |= DirtyFillGeom;
+ if (d.fillTextureProviderItem != nullptr)
+ QQuickItemPrivate::get(d.fillTextureProviderItem)->derefWindow();
+ d.fillTextureProviderItem = textureProviderItem;
+ if (d.fillTextureProviderItem != nullptr)
+ QQuickItemPrivate::get(d.fillTextureProviderItem)->refWindow(m_item->window());
+ d.syncDirty |= DirtyFillTexture;
+}
+
+void QQuickShapeGenericRenderer::handleSceneChange(QQuickWindow *window)
+{
+ for (auto &pathData : m_sp) {
+ if (pathData.fillTextureProviderItem != nullptr) {
+ if (window == nullptr)
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->derefWindow();
+ else
+ QQuickItemPrivate::get(pathData.fillTextureProviderItem)->refWindow(window);
+ }
+ }
+}
+
+
+void QQuickShapeGenericRenderer::setFillTransform(int index, const QSGTransform &transform)
+{
+ ShapePathData &d(m_sp[index]);
+ d.fillTransform = transform;
+ d.syncDirty |= DirtyFillTransform;
+}
+
void QQuickShapeGenericRenderer::setTriangulationScale(qreal scale)
{
// No dirty, this is called at the start of every sync. Just store the value.
@@ -491,7 +549,7 @@ void QQuickShapeGenericRenderer::updateNode()
QQuickShapeGenericNode *node = *nodePtr;
if (m_accDirty & DirtyList)
- d.effectiveDirty |= DirtyFillGeom | DirtyStrokeGeom | DirtyColor | DirtyFillGradient;
+ d.effectiveDirty |= DirtyFillGeom | DirtyStrokeGeom | DirtyColor | DirtyFillGradient | DirtyFillTransform | DirtyFillTexture;
if (!d.effectiveDirty) {
prevNode = node;
@@ -545,13 +603,43 @@ void QQuickShapeGenericRenderer::updateShadowDataInNode(ShapePathData *d, QQuick
if (d->effectiveDirty & DirtyFillGradient)
n->m_fillGradient = d->fillGradient;
}
+ if (d->effectiveDirty & DirtyFillTexture) {
+ bool needsUpdate = d->fillTextureProviderItem == nullptr && n->m_fillTextureProvider != nullptr;
+ if (!needsUpdate
+ && d->fillTextureProviderItem != nullptr
+ && n->m_fillTextureProvider != d->fillTextureProviderItem->textureProvider()) {
+ needsUpdate = true;
+ }
+
+ if (needsUpdate) {
+ if (n->m_fillTextureProvider != nullptr) {
+ QObject::disconnect(n->m_fillTextureProvider, &QSGTextureProvider::textureChanged,
+ n, &QQuickShapeGenericStrokeFillNode::handleTextureChanged);
+ QObject::disconnect(n->m_fillTextureProvider, &QSGTextureProvider::destroyed,
+ n, &QQuickShapeGenericStrokeFillNode::handleTextureProviderDestroyed);
+ }
+
+ n->m_fillTextureProvider = d->fillTextureProviderItem == nullptr
+ ? nullptr
+ : d->fillTextureProviderItem->textureProvider();
+
+ if (n->m_fillTextureProvider != nullptr) {
+ QObject::connect(n->m_fillTextureProvider, &QSGTextureProvider::textureChanged,
+ n, &QQuickShapeGenericStrokeFillNode::handleTextureChanged);
+ QObject::connect(n->m_fillTextureProvider, &QSGTextureProvider::destroyed,
+ n, &QQuickShapeGenericStrokeFillNode::handleTextureProviderDestroyed);
+ }
+ }
+ }
+ if (d->effectiveDirty & DirtyFillTransform)
+ n->m_fillTransform = d->fillTransform;
}
void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGenericNode *node)
{
if (!node->m_fillNode)
return;
- if (!(d->effectiveDirty & (DirtyFillGeom | DirtyColor | DirtyFillGradient)))
+ if (!(d->effectiveDirty & (DirtyFillGeom | DirtyColor | DirtyFillGradient | DirtyFillTransform | DirtyFillTexture)))
return;
// Make a copy of the data that will be accessed by the material on
@@ -584,17 +672,21 @@ void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGen
Q_UNREACHABLE_RETURN();
}
n->activateMaterial(m_item->window(), gradMat);
- if (d->effectiveDirty & DirtyFillGradient) {
+ if (d->effectiveDirty & (DirtyFillGradient | DirtyFillTransform)) {
// Gradients are implemented via a texture-based material.
n->markDirty(QSGNode::DirtyMaterial);
- // stop here if only the gradient changed; no need to touch the geometry
+ // stop here if only the gradient or filltransform changed; no need to touch the geometry
if (!(d->effectiveDirty & DirtyFillGeom))
return;
}
+ } else if (d->fillTextureProviderItem != nullptr) {
+ n->activateMaterial(m_item->window(), QQuickShapeGenericStrokeFillNode::MatTextureFill);
+ if (d->effectiveDirty & DirtyFillTexture)
+ n->markDirty(QSGNode::DirtyMaterial);
} else {
n->activateMaterial(m_item->window(), QQuickShapeGenericStrokeFillNode::MatSolidColor);
// fast path for updating only color values when no change in vertex positions
- if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyFillGeom)) {
+ if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyFillGeom) && d->fillTextureProviderItem == nullptr) {
ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData());
for (int i = 0; i < g->vertexCount(); ++i)
vdst[i].set(vdst[i].x, vdst[i].y, d->fillColor);
@@ -613,6 +705,7 @@ void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGen
g->allocate(d->fillVertices.size(), indexCount);
}
g->setDrawingMode(QSGGeometry::DrawTriangles);
+
memcpy(g->vertexData(), d->fillVertices.constData(), g->vertexCount() * g->sizeOfVertex());
memcpy(g->indexData(), d->fillIndices.constData(), g->indexCount() * g->sizeOfIndex());
@@ -703,6 +796,18 @@ QSGMaterial *QQuickShapeGenericMaterialFactory::createConicalGradient(QQuickWind
return nullptr;
}
+QSGMaterial *QQuickShapeGenericMaterialFactory::createTextureFill(QQuickWindow *window,
+ QQuickShapeGenericStrokeFillNode *node)
+{
+ QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi();
+
+ if (api == QSGRendererInterface::OpenGL || QSGRendererInterface::isApiRhiBased(api))
+ return new QQuickShapeTextureFillMaterial(node);
+
+ qWarning("Texture fill material: Unsupported graphics API %d", api);
+ return nullptr;
+}
+
QQuickShapeLinearGradientRhiShader::QQuickShapeLinearGradientRhiShader(int viewCount)
{
setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/lineargradient.vert.qsb"), viewCount);
@@ -716,7 +821,7 @@ bool QQuickShapeLinearGradientRhiShader::updateUniformData(RenderState &state,
QQuickShapeLinearGradientMaterial *m = static_cast<QQuickShapeLinearGradientMaterial *>(newMaterial);
bool changed = false;
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 84);
+ Q_ASSERT(buf->size() >= 84 + 64);
const int shaderMatrixCount = newMaterial->viewCount();
const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
@@ -730,22 +835,28 @@ bool QQuickShapeLinearGradientRhiShader::updateUniformData(RenderState &state,
QQuickShapeGenericStrokeFillNode *node = m->node();
+ if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
+ memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
+ m_fillTransform = node->m_fillTransform;
+ changed = true;
+ }
+
if (!oldMaterial || m_gradA.x() != node->m_fillGradient.a.x() || m_gradA.y() != node->m_fillGradient.a.y()) {
m_gradA = QVector2D(node->m_fillGradient.a.x(), node->m_fillGradient.a.y());
Q_ASSERT(sizeof(m_gradA) == 8);
- memcpy(buf->data() + 64 * shaderMatrixCount, &m_gradA, 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_gradA, 8);
changed = true;
}
if (!oldMaterial || m_gradB.x() != node->m_fillGradient.b.x() || m_gradB.y() != node->m_fillGradient.b.y()) {
m_gradB = QVector2D(node->m_fillGradient.b.x(), node->m_fillGradient.b.y());
- memcpy(buf->data() + 64 * shaderMatrixCount + 8, &m_gradB, 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_gradB, 8);
changed = true;
}
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
- memcpy(buf->data() + 64 * shaderMatrixCount + 8 + 8, &opacity, 4);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8, &opacity, 4);
changed = true;
}
@@ -808,6 +919,9 @@ int QQuickShapeLinearGradientMaterial::compare(const QSGMaterial *other) const
return d;
}
+ if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
+ return d;
+
return 0;
}
@@ -830,7 +944,7 @@ bool QQuickShapeRadialGradientRhiShader::updateUniformData(RenderState &state,
QQuickShapeRadialGradientMaterial *m = static_cast<QQuickShapeRadialGradientMaterial *>(newMaterial);
bool changed = false;
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 92);
+ Q_ASSERT(buf->size() >= 92 + 64);
const int shaderMatrixCount = newMaterial->viewCount();
const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
@@ -844,6 +958,12 @@ bool QQuickShapeRadialGradientRhiShader::updateUniformData(RenderState &state,
QQuickShapeGenericStrokeFillNode *node = m->node();
+ if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
+ memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
+ m_fillTransform = node->m_fillTransform;
+ changed = true;
+ }
+
const QPointF centerPoint = node->m_fillGradient.a;
const QPointF focalPoint = node->m_fillGradient.b;
const QPointF focalToCenter = centerPoint - focalPoint;
@@ -853,32 +973,32 @@ bool QQuickShapeRadialGradientRhiShader::updateUniformData(RenderState &state,
if (!oldMaterial || m_focalPoint.x() != focalPoint.x() || m_focalPoint.y() != focalPoint.y()) {
m_focalPoint = QVector2D(focalPoint.x(), focalPoint.y());
Q_ASSERT(sizeof(m_focalPoint) == 8);
- memcpy(buf->data() + 64 * shaderMatrixCount, &m_focalPoint, 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_focalPoint, 8);
changed = true;
}
if (!oldMaterial || m_focalToCenter.x() != focalToCenter.x() || m_focalToCenter.y() != focalToCenter.y()) {
m_focalToCenter = QVector2D(focalToCenter.x(), focalToCenter.y());
Q_ASSERT(sizeof(m_focalToCenter) == 8);
- memcpy(buf->data() + 64 * shaderMatrixCount + 8, &m_focalToCenter, 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_focalToCenter, 8);
changed = true;
}
if (!oldMaterial || m_centerRadius != centerRadius) {
m_centerRadius = centerRadius;
- memcpy(buf->data() + 64 * shaderMatrixCount + 8 + 8, &m_centerRadius, 4);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8, &m_centerRadius, 4);
changed = true;
}
if (!oldMaterial || m_focalRadius != focalRadius) {
m_focalRadius = focalRadius;
- memcpy(buf->data() + 64 * shaderMatrixCount + 8 + 8 + 4, &m_focalRadius, 4);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8 + 4, &m_focalRadius, 4);
changed = true;
}
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
- memcpy(buf->data() + 64 * shaderMatrixCount + 8 + 8 + 4 + 4, &opacity, 4);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 8 + 4 + 4, &opacity, 4);
changed = true;
}
@@ -946,6 +1066,9 @@ int QQuickShapeRadialGradientMaterial::compare(const QSGMaterial *other) const
return d;
}
+ if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
+ return d;
+
return 0;
}
@@ -968,7 +1091,7 @@ bool QQuickShapeConicalGradientRhiShader::updateUniformData(RenderState &state,
QQuickShapeConicalGradientMaterial *m = static_cast<QQuickShapeConicalGradientMaterial *>(newMaterial);
bool changed = false;
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 80);
+ Q_ASSERT(buf->size() >= 80 + 64);
const int shaderMatrixCount = newMaterial->viewCount();
const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
@@ -982,25 +1105,31 @@ bool QQuickShapeConicalGradientRhiShader::updateUniformData(RenderState &state,
QQuickShapeGenericStrokeFillNode *node = m->node();
+ if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
+ memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
+ m_fillTransform = node->m_fillTransform;
+ changed = true;
+ }
+
const QPointF centerPoint = node->m_fillGradient.a;
const float angle = -qDegreesToRadians(node->m_fillGradient.v0);
if (!oldMaterial || m_centerPoint.x() != centerPoint.x() || m_centerPoint.y() != centerPoint.y()) {
m_centerPoint = QVector2D(centerPoint.x(), centerPoint.y());
Q_ASSERT(sizeof(m_centerPoint) == 8);
- memcpy(buf->data() + 64 * shaderMatrixCount, &m_centerPoint, 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_centerPoint, 8);
changed = true;
}
if (!oldMaterial || m_angle != angle) {
m_angle = angle;
- memcpy(buf->data() + 64 * shaderMatrixCount + 8, &m_angle, 4);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &m_angle, 4);
changed = true;
}
if (state.isOpacityDirty()) {
const float opacity = state.opacity();
- memcpy(buf->data() + 64 * shaderMatrixCount + 8 + 4, &opacity, 4);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8 + 4, &opacity, 4);
changed = true;
}
@@ -1059,6 +1188,9 @@ int QQuickShapeConicalGradientMaterial::compare(const QSGMaterial *other) const
return d;
}
+ if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
+ return d;
+
return 0;
}
@@ -1068,6 +1200,139 @@ QSGMaterialShader *QQuickShapeConicalGradientMaterial::createShader(QSGRendererI
return new QQuickShapeConicalGradientRhiShader(viewCount());
}
+QQuickShapeTextureFillRhiShader::QQuickShapeTextureFillRhiShader(int viewCount)
+{
+ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/texturefill.vert.qsb"), viewCount);
+ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/shapes/shaders_ng/texturefill.frag.qsb"), viewCount);
+}
+
+bool QQuickShapeTextureFillRhiShader::updateUniformData(RenderState &state,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+{
+ Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
+ QQuickShapeTextureFillMaterial *m = static_cast<QQuickShapeTextureFillMaterial *>(newMaterial);
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+ const int shaderMatrixCount = newMaterial->viewCount();
+ const int matrixCount = qMin(state.projectionMatrixCount(), shaderMatrixCount);
+ Q_ASSERT(buf->size() >= 64 * shaderMatrixCount + 64 + 8 + 4);
+
+ if (state.isMatrixDirty()) {
+ for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
+ const QMatrix4x4 m = state.combinedMatrix();
+ memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
+ changed = true;
+ }
+ }
+
+ QQuickShapeGenericStrokeFillNode *node = m->node();
+
+ if (!oldMaterial || m_fillTransform != node->m_fillTransform) {
+ memcpy(buf->data() + 64 * shaderMatrixCount, node->m_fillTransform.invertedData(), 64);
+ m_fillTransform = node->m_fillTransform;
+ changed = true;
+ }
+
+ const QSizeF boundsSize = node->m_fillTextureProvider != nullptr && node->m_fillTextureProvider->texture() != nullptr
+ ? node->m_fillTextureProvider->texture()->textureSize()
+ : QSizeF(0, 0);
+
+
+ const QVector2D boundsVector(boundsSize.width() / state.devicePixelRatio(),
+ boundsSize.height() / state.devicePixelRatio());
+ if (!oldMaterial || m_boundsSize != boundsVector) {
+ m_boundsSize = boundsVector;
+ Q_ASSERT(sizeof(m_boundsSize) == 8);
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64, &m_boundsSize, 8);
+ changed = true;
+ }
+
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(buf->data() + 64 * shaderMatrixCount + 64 + 8, &opacity, 4);
+ changed = true;
+ }
+
+ return changed;
+}
+
+void QQuickShapeTextureFillRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *)
+{
+ if (binding != 1)
+ return;
+
+ QQuickShapeTextureFillMaterial *m = static_cast<QQuickShapeTextureFillMaterial *>(newMaterial);
+ QQuickShapeGenericStrokeFillNode *node = m->node();
+ if (node->m_fillTextureProvider != nullptr) {
+ QSGTexture *providedTexture = node->m_fillTextureProvider->texture();
+ if (providedTexture != nullptr) {
+ if (providedTexture->isAtlasTexture()) {
+ // Create a non-atlas copy to make texture coordinate wrapping work. This
+ // texture copy is owned by the QSGTexture so memory is managed with the original
+ // texture provider.
+ QSGTexture *newTexture = providedTexture->removedFromAtlas(state.resourceUpdateBatch());
+ if (newTexture != nullptr)
+ providedTexture = newTexture;
+ }
+
+ providedTexture->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+ *texture = providedTexture;
+ return;
+ }
+ }
+
+ if (m->dummyTexture() == nullptr) {
+ QSGPlainTexture *dummyTexture = new QSGPlainTexture;
+ dummyTexture->setFiltering(QSGTexture::Nearest);
+ dummyTexture->setHorizontalWrapMode(QSGTexture::Repeat);
+ dummyTexture->setVerticalWrapMode(QSGTexture::Repeat);
+ QImage img(128, 128, QImage::Format_ARGB32_Premultiplied);
+ img.fill(0);
+ dummyTexture->setImage(img);
+ dummyTexture->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+
+ m->setDummyTexture(dummyTexture);
+ }
+
+ *texture = m->dummyTexture();
+}
+
+QQuickShapeTextureFillMaterial::~QQuickShapeTextureFillMaterial()
+{
+ delete m_dummyTexture;
+}
+
+QSGMaterialType *QQuickShapeTextureFillMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+int QQuickShapeTextureFillMaterial::compare(const QSGMaterial *other) const
+{
+ Q_ASSERT(other && type() == other->type());
+ const QQuickShapeTextureFillMaterial *m = static_cast<const QQuickShapeTextureFillMaterial *>(other);
+
+ QQuickShapeGenericStrokeFillNode *a = node();
+ QQuickShapeGenericStrokeFillNode *b = m->node();
+ Q_ASSERT(a && b);
+ if (a == b)
+ return 0;
+
+ if (int d = a->m_fillTransform.compareTo(b->m_fillTransform))
+ return d;
+
+ const qintptr diff = qintptr(a->m_fillTextureProvider) - qintptr(b->m_fillTextureProvider);
+ return diff < 0 ? -1 : (diff > 0 ? 1 : 0);
+}
+
+QSGMaterialShader *QQuickShapeTextureFillMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
+{
+ Q_UNUSED(renderMode);
+ return new QQuickShapeTextureFillRhiShader(viewCount());
+}
+
QT_END_NAMESPACE
#include "moc_qquickshapegenericrenderer_p.cpp"
diff --git a/src/quickshapes/qquickshapegenericrenderer_p.h b/src/quickshapes/qquickshapegenericrenderer_p.h
index 6877b674e0..7f5ce81da0 100644
--- a/src/quickshapes/qquickshapegenericrenderer_p.h
+++ b/src/quickshapes/qquickshapegenericrenderer_p.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQUICKSHAPEGENERICRENDERER_P_H
@@ -40,7 +40,9 @@ public:
DirtyStrokeGeom = 0x02,
DirtyColor = 0x04,
DirtyFillGradient = 0x08,
- DirtyList = 0x10 // only for accDirty
+ DirtyFillTransform = 0x10,
+ DirtyFillTexture = 0x20,
+ DirtyList = 0x40 // only for accDirty
};
QQuickShapeGenericRenderer(QQuickItem *item)
@@ -64,10 +66,13 @@ public:
void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
qreal dashOffset, const QVector<qreal> &dashPattern) override;
void setFillGradient(int index, QQuickShapeGradient *gradient) override;
+ void setFillTextureProvider(int index, QQuickItem *textureProviderItem) override;
+ void setFillTransform(int index, const QSGTransform &transform) override;
void setTriangulationScale(qreal scale) override;
void endSync(bool async) override;
void setAsyncCallback(void (*)(void *), void *) override;
Flags flags() const override { return SupportsAsync; }
+ void handleSceneChange(QQuickWindow *window) override;
void updateNode() override;
@@ -75,6 +80,7 @@ public:
struct Color4ub { unsigned char r, g, b, a; };
typedef QVector<QSGGeometry::ColoredPoint2D> VertexContainerType;
+ typedef QVector<QSGGeometry::TexturedPoint2D> TexturedVertexContainerType;
typedef QVector<quint32> IndexContainerType;
static void triangulateFill(const QPainterPath &path,
@@ -103,6 +109,8 @@ private:
QPainterPath path;
FillGradientType fillGradientActive;
QSGGradientCache::GradientDesc fillGradient;
+ QQuickItem *fillTextureProviderItem = nullptr;
+ QSGTransform fillTransform;
VertexContainerType fillVertices;
IndexContainerType fillIndices;
QSGGeometry::Type indexType;
@@ -174,8 +182,9 @@ Q_SIGNALS:
void done(QQuickShapeStrokeRunnable *self);
};
-class QQuickShapeGenericStrokeFillNode : public QSGGeometryNode
+class QQuickShapeGenericStrokeFillNode : public QObject, public QSGGeometryNode
{
+ Q_OBJECT
public:
QQuickShapeGenericStrokeFillNode(QQuickWindow *window);
@@ -183,13 +192,21 @@ public:
MatSolidColor,
MatLinearGradient,
MatRadialGradient,
- MatConicalGradient
+ MatConicalGradient,
+ MatTextureFill
};
void activateMaterial(QQuickWindow *window, Material m);
// shadow data for custom materials
QSGGradientCache::GradientDesc m_fillGradient;
+ QSGTextureProvider *m_fillTextureProvider = nullptr;
+ QSGTransform m_fillTransform;
+ void preprocess() override;
+
+private Q_SLOTS:
+ void handleTextureChanged();
+ void handleTextureProviderDestroyed();
private:
QScopedPointer<QSGMaterial> m_material;
@@ -212,6 +229,7 @@ public:
static QSGMaterial *createLinearGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
static QSGMaterial *createRadialGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
static QSGMaterial *createConicalGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
+ static QSGMaterial *createTextureFill(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
};
class QQuickShapeLinearGradientRhiShader : public QSGMaterialShader
@@ -225,6 +243,7 @@ public:
QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
private:
+ QSGTransform m_fillTransform;
QVector2D m_gradA;
QVector2D m_gradB;
};
@@ -264,6 +283,7 @@ public:
QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
private:
+ QSGTransform m_fillTransform;
QVector2D m_focalPoint;
QVector2D m_focalToCenter;
float m_centerRadius;
@@ -300,6 +320,7 @@ public:
QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
private:
+ QSGTransform m_fillTransform;
QVector2D m_centerPoint;
float m_angle;
};
@@ -323,6 +344,53 @@ private:
QQuickShapeGenericStrokeFillNode *m_node;
};
+class QQuickShapeTextureFillRhiShader : public QSGMaterialShader
+{
+public:
+ QQuickShapeTextureFillRhiShader(int viewCount);
+
+ bool updateUniformData(RenderState &state, QSGMaterial *newMaterial,
+ QSGMaterial *oldMaterial) override;
+ void updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
+
+private:
+ QSGTransform m_fillTransform;
+ QVector2D m_boundsOffset;
+ QVector2D m_boundsSize;
+};
+
+class QQuickShapeTextureFillMaterial : public QSGMaterial
+{
+public:
+ QQuickShapeTextureFillMaterial(QQuickShapeGenericStrokeFillNode *node)
+ : m_node(node)
+ {
+ setFlag(Blending | RequiresFullMatrix);
+ }
+ ~QQuickShapeTextureFillMaterial() override;
+
+ QSGMaterialType *type() const override;
+ int compare(const QSGMaterial *other) const override;
+ QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override;
+
+ QQuickShapeGenericStrokeFillNode *node() const { return m_node; }
+
+ QSGPlainTexture *dummyTexture() const
+ {
+ return m_dummyTexture;
+ }
+
+ void setDummyTexture(QSGPlainTexture *texture)
+ {
+ m_dummyTexture = texture;
+ }
+
+private:
+ QQuickShapeGenericStrokeFillNode *m_node;
+ QSGPlainTexture *m_dummyTexture = nullptr;
+};
+
QT_END_NAMESPACE
#endif // QQUICKSHAPEGENERICRENDERER_P_H
diff --git a/src/quickshapes/qquickshapesoftwarerenderer.cpp b/src/quickshapes/qquickshapesoftwarerenderer.cpp
index 60efcf1db9..f1a2e3dc67 100644
--- a/src/quickshapes/qquickshapesoftwarerenderer.cpp
+++ b/src/quickshapes/qquickshapesoftwarerenderer.cpp
@@ -138,6 +138,27 @@ void QQuickShapeSoftwareRenderer::setFillGradient(int index, QQuickShapeGradient
m_accDirty |= DirtyBrush;
}
+void QQuickShapeSoftwareRenderer::setFillTextureProvider(int index, QQuickItem *textureProviderItem)
+{
+ Q_UNUSED(index);
+ Q_UNUSED(textureProviderItem);
+}
+
+void QQuickShapeSoftwareRenderer::handleSceneChange(QQuickWindow *window)
+{
+ Q_UNUSED(window);
+ // No action needed
+}
+
+void QQuickShapeSoftwareRenderer::setFillTransform(int index, const QSGTransform &transform)
+{
+ ShapePathGuiData &d(m_sp[index]);
+ if (!(transform.isIdentity() && d.brush.transform().isIdentity())) // No need to copy if both==I
+ d.brush.setTransform(transform.matrix().toTransform());
+ d.dirty |= DirtyBrush;
+ m_accDirty |= DirtyBrush;
+}
+
void QQuickShapeSoftwareRenderer::endSync(bool)
{
}
diff --git a/src/quickshapes/qquickshapesoftwarerenderer_p.h b/src/quickshapes/qquickshapesoftwarerenderer_p.h
index d08145bb1b..94eded84e5 100644
--- a/src/quickshapes/qquickshapesoftwarerenderer_p.h
+++ b/src/quickshapes/qquickshapesoftwarerenderer_p.h
@@ -47,7 +47,10 @@ public:
void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
qreal dashOffset, const QVector<qreal> &dashPattern) override;
void setFillGradient(int index, QQuickShapeGradient *gradient) override;
+ void setFillTextureProvider(int index, QQuickItem *textureProviderItem) override;
+ void setFillTransform(int index, const QSGTransform &transform) override;
void endSync(bool async) override;
+ void handleSceneChange(QQuickWindow *window) override;
void updateNode() override;
diff --git a/src/quickshapes/shaders_ng/conicalgradient.frag b/src/quickshapes/shaders_ng/conicalgradient.frag
index 7707d55deb..59862f991a 100644
--- a/src/quickshapes/shaders_ng/conicalgradient.frag
+++ b/src/quickshapes/shaders_ng/conicalgradient.frag
@@ -14,6 +14,7 @@ layout(std140, binding = 0) uniform buf {
#else
mat4 matrix;
#endif
+ mat4 gradientMatrix;
vec2 translationPoint;
float angle;
float opacity;
diff --git a/src/quickshapes/shaders_ng/conicalgradient.vert b/src/quickshapes/shaders_ng/conicalgradient.vert
index c092198724..cdaab16842 100644
--- a/src/quickshapes/shaders_ng/conicalgradient.vert
+++ b/src/quickshapes/shaders_ng/conicalgradient.vert
@@ -11,6 +11,7 @@ layout(std140, binding = 0) uniform buf {
#else
mat4 matrix;
#endif
+ mat4 gradientMatrix;
vec2 translationPoint;
float angle;
float opacity;
@@ -18,7 +19,8 @@ layout(std140, binding = 0) uniform buf {
void main()
{
- coord = vertexCoord.xy - ubuf.translationPoint;
+ vec2 gradVertexCoord = (ubuf.gradientMatrix * vertexCoord).xy;
+ coord = gradVertexCoord - ubuf.translationPoint;
#if QSHADER_VIEW_COUNT >= 2
gl_Position = ubuf.matrix[gl_ViewIndex] * vertexCoord;
#else
diff --git a/src/quickshapes/shaders_ng/lineargradient.frag b/src/quickshapes/shaders_ng/lineargradient.frag
index 6dc4c7d5ca..b6f0dc172a 100644
--- a/src/quickshapes/shaders_ng/lineargradient.frag
+++ b/src/quickshapes/shaders_ng/lineargradient.frag
@@ -14,6 +14,7 @@ layout(std140, binding = 0) uniform buf {
#else
mat4 matrix;
#endif
+ mat4 gradientMatrix;
vec2 gradStart;
vec2 gradEnd;
float opacity;
diff --git a/src/quickshapes/shaders_ng/lineargradient.vert b/src/quickshapes/shaders_ng/lineargradient.vert
index b453739230..13168b1c0f 100644
--- a/src/quickshapes/shaders_ng/lineargradient.vert
+++ b/src/quickshapes/shaders_ng/lineargradient.vert
@@ -11,6 +11,7 @@ layout(std140, binding = 0) uniform buf {
#else
mat4 matrix;
#endif
+ mat4 gradientMatrix;
vec2 gradStart;
vec2 gradEnd;
float opacity;
@@ -18,8 +19,9 @@ layout(std140, binding = 0) uniform buf {
void main()
{
+ vec2 gradVertexCoord = (ubuf.gradientMatrix * vertexCoord).xy;
vec2 gradVec = ubuf.gradEnd - ubuf.gradStart;
- gradTabIndex = dot(gradVec, vertexCoord.xy - ubuf.gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y);
+ gradTabIndex = dot(gradVec, gradVertexCoord - ubuf.gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y);
#if QSHADER_VIEW_COUNT >= 2
gl_Position = ubuf.matrix[gl_ViewIndex] * vertexCoord;
#else
diff --git a/src/quickshapes/shaders_ng/radialgradient.frag b/src/quickshapes/shaders_ng/radialgradient.frag
index bbc68b2ce7..cfbb44ac69 100644
--- a/src/quickshapes/shaders_ng/radialgradient.frag
+++ b/src/quickshapes/shaders_ng/radialgradient.frag
@@ -14,6 +14,7 @@ layout(std140, binding = 0) uniform buf {
#else
mat4 matrix;
#endif
+ mat4 gradientMatrix;
vec2 translationPoint;
vec2 focalToCenter;
float centerRadius;
diff --git a/src/quickshapes/shaders_ng/radialgradient.vert b/src/quickshapes/shaders_ng/radialgradient.vert
index 6d3dfce745..16c8406b23 100644
--- a/src/quickshapes/shaders_ng/radialgradient.vert
+++ b/src/quickshapes/shaders_ng/radialgradient.vert
@@ -11,6 +11,7 @@ layout(std140, binding = 0) uniform buf {
#else
mat4 matrix;
#endif
+ mat4 gradientMatrix;
vec2 translationPoint;
vec2 focalToCenter;
float centerRadius;
@@ -20,7 +21,8 @@ layout(std140, binding = 0) uniform buf {
void main()
{
- coord = vertexCoord.xy - ubuf.translationPoint;
+ vec2 gradVertexCoord = (ubuf.gradientMatrix * vertexCoord).xy;
+ coord = gradVertexCoord - ubuf.translationPoint;
#if QSHADER_VIEW_COUNT >= 2
gl_Position = ubuf.matrix[gl_ViewIndex] * vertexCoord;
#else
diff --git a/src/quickshapes/shaders_ng/texturefill.frag b/src/quickshapes/shaders_ng/texturefill.frag
new file mode 100644
index 0000000000..c8a7f280f1
--- /dev/null
+++ b/src/quickshapes/shaders_ng/texturefill.frag
@@ -0,0 +1,25 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#version 440
+
+layout(location = 0) in vec2 textureCoord;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D sourceTexture;
+
+layout(std140, binding = 0) uniform buf {
+#if QSHADER_VIEW_COUNT >= 2
+ mat4 qt_Matrix[QSHADER_VIEW_COUNT];
+#else
+ mat4 qt_Matrix;
+#endif
+ mat4 fillMatrix;
+ vec2 boundsSize;
+ float qt_Opacity;
+} ubuf;
+
+void main()
+{
+ fragColor = texture(sourceTexture, textureCoord) * ubuf.qt_Opacity;
+}
diff --git a/src/quickshapes/shaders_ng/texturefill.vert b/src/quickshapes/shaders_ng/texturefill.vert
new file mode 100644
index 0000000000..c9d52469dc
--- /dev/null
+++ b/src/quickshapes/shaders_ng/texturefill.vert
@@ -0,0 +1,31 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#version 440
+
+layout(location = 0) in vec4 vertexCoord;
+layout(location = 1) in vec4 vertexColor;
+
+layout(location = 0) out vec2 textureCoord;
+
+layout(std140, binding = 0) uniform buf {
+#if QSHADER_VIEW_COUNT >= 2
+ mat4 qt_Matrix[QSHADER_VIEW_COUNT];
+#else
+ mat4 qt_Matrix;
+#endif
+ mat4 fillMatrix;
+ vec2 boundsSize;
+ float qt_Opacity;
+} ubuf;
+
+void main()
+{
+ vec2 xformed = (ubuf.fillMatrix * vertexCoord).xy;
+ textureCoord = vec2(xformed.x / ubuf.boundsSize.x, xformed.y / ubuf.boundsSize.y);
+#if QSHADER_VIEW_COUNT >= 2
+ gl_Position = ubuf.qt_Matrix[gl_ViewIndex] * vertexCoord;
+#else
+ gl_Position = ubuf.qt_Matrix * vertexCoord;
+#endif
+}
diff --git a/src/quicktemplates/CMakeLists.txt b/src/quicktemplates/CMakeLists.txt
index 441649a46a..6a98ce2f89 100644
--- a/src/quicktemplates/CMakeLists.txt
+++ b/src/quicktemplates/CMakeLists.txt
@@ -46,6 +46,12 @@ qt_internal_add_qml_module(QuickTemplates2
qquicklabel.cpp qquicklabel_p.h
qquicklabel_p_p.h
qquickmenuseparator.cpp qquickmenuseparator_p.h
+ qquicknativeicon_p.h
+ qquicknativeicon.cpp
+ qquicknativeiconloader_p.h
+ qquicknativeiconloader.cpp
+ qquicknativemenuitem_p.h
+ qquicknativemenuitem.cpp
qquickoverlay.cpp qquickoverlay_p.h
qquickoverlay_p_p.h
qquickpage.cpp qquickpage_p.h
@@ -61,6 +67,8 @@ qt_internal_add_qml_module(QuickTemplates2
qquickpopupitem_p_p.h
qquickpopuppositioner.cpp
qquickpopuppositioner_p_p.h
+ qquickpopupwindow.cpp
+ qquickpopupwindow_p_p.h
qquickpresshandler.cpp
qquickpresshandler_p_p.h
qquickprogressbar.cpp qquickprogressbar_p.h
@@ -115,7 +123,6 @@ qt_internal_add_qml_module(QuickTemplates2
Qt::Core
Qt::Gui
Qt::Quick
- GENERATE_CPP_EXPORTS
)
qt_internal_extend_target(QuickTemplates2 CONDITION TARGET Qt::QmlModels
diff --git a/src/quicktemplates/qquickabstractbutton.cpp b/src/quicktemplates/qquickabstractbutton.cpp
index 0c1af73e55..ff2d9715c1 100644
--- a/src/quicktemplates/qquickabstractbutton.cpp
+++ b/src/quicktemplates/qquickabstractbutton.cpp
@@ -18,6 +18,8 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpa/qplatformtheme.h>
#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuick/private/qquickaccessibleattached_p.h>
#include <QtQml/qqmllist.h>
QT_BEGIN_NAMESPACE
@@ -64,7 +66,7 @@ QT_BEGIN_NAMESPACE
This signal is emitted when the button is interactively clicked by the user via touch, mouse, or keyboard.
- \sa {Call a C++ function from QML when a Button is clicked}
+ \sa click(), animateClick(), {Call a C++ function from QML when a Button is clicked}
*/
/*!
@@ -889,6 +891,12 @@ void QQuickAbstractButton::setAction(QQuickAction *action)
setEnabled(action->isEnabled());
}
+#if QT_CONFIG(accessibility)
+ auto attached = qobject_cast<QQuickAccessibleAttached*>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(this, true));
+ Q_ASSERT(attached);
+ attached->setProxying(qobject_cast<QQuickAccessibleAttached*>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(action, true)));
+#endif
+
d->action = action;
if (oldText != text())
@@ -1051,6 +1059,8 @@ qreal QQuickAbstractButton::implicitIndicatorHeight() const
\qmlmethod void QtQuick.Controls::AbstractButton::toggle()
Toggles the checked state of the button.
+
+ \sa click(), animateClick()
*/
void QQuickAbstractButton::toggle()
{
@@ -1058,6 +1068,81 @@ void QQuickAbstractButton::toggle()
setChecked(!d->checked);
}
+/*!
+ \since Qt 6.8
+ \qmlmethod void QtQuick.Controls::AbstractButton::click()
+
+ Simulates the button being clicked with no delay between press and release.
+
+ All signals associated with a click are emitted as appropriate.
+
+ If the \l focusPolicy includes \c Qt.ClickFocus, \l activeFocus will
+ become \c true.
+
+ This function does nothing if the button is \l {enabled}{disabled}.
+
+ Calling this function again before the button is released resets
+ the release timer.
+
+ \sa animateClick(), pressed(), released(), clicked()
+*/
+void QQuickAbstractButton::click()
+{
+ Q_D(QQuickAbstractButton);
+ if (!isEnabled())
+ return;
+
+ // QQuickItemPrivate::deliverPointerEvent calls setFocusIfNeeded on real clicks,
+ // so we need to do it ourselves.
+ const bool setFocusOnPress = !QGuiApplication::styleHints()->setFocusOnTouchRelease();
+ if (setFocusOnPress && focusPolicy() & Qt::ClickFocus)
+ forceActiveFocus(Qt::MouseFocusReason);
+
+ const QPointF eventPos(d->width / 2, d->height / 2);
+ d->handlePress(eventPos, 0);
+ d->handleRelease(eventPos, 0);
+}
+
+/*!
+ \since Qt 6.8
+ \qmlmethod void QtQuick.Controls::AbstractButton::animateClick()
+
+ Simulates the button being clicked, with a 100 millisecond delay
+ between press and release, animating its visual state in the
+ process.
+
+ All signals associated with a click are emitted as appropriate.
+
+ If the \l focusPolicy includes \c Qt.ClickFocus, \l activeFocus will
+ become \c true.
+
+ This function does nothing if the button is \l {enabled}{disabled}.
+
+ Calling this function again before the button is released resets
+ the release timer.
+
+ \sa click(), pressed(), released(), clicked()
+*/
+void QQuickAbstractButton::animateClick()
+{
+ Q_D(QQuickAbstractButton);
+ if (!isEnabled())
+ return;
+
+ // See comment in click() for why we do this.
+ const bool setFocusOnPress = !QGuiApplication::styleHints()->setFocusOnTouchRelease();
+ if (setFocusOnPress && focusPolicy() & Qt::ClickFocus)
+ forceActiveFocus(Qt::MouseFocusReason);
+
+ // If the timer was already running, kill it so we can restart it.
+ if (d->animateTimer != 0)
+ killTimer(d->animateTimer);
+ else
+ d->handlePress(QPointF(d->width / 2, d->height / 2), 0);
+
+ d->animateTimer = startTimer(100);
+}
+
void QQuickAbstractButton::componentComplete()
{
Q_D(QQuickAbstractButton);
@@ -1158,6 +1243,12 @@ void QQuickAbstractButton::timerEvent(QTimerEvent *event)
emit released();
d->trigger();
emit pressed();
+ } else if (event->timerId() == d->animateTimer) {
+ const bool setFocusOnRelease = QGuiApplication::styleHints()->setFocusOnTouchRelease();
+ if (setFocusOnRelease && focusPolicy() & Qt::ClickFocus)
+ forceActiveFocus(Qt::MouseFocusReason);
+ d->handleRelease(QPointF(d->width / 2, d->height / 2), 0);
+ d->animateTimer = 0;
}
}
diff --git a/src/quicktemplates/qquickabstractbutton_p.h b/src/quicktemplates/qquickabstractbutton_p.h
index 0ac27db156..c9e7407920 100644
--- a/src/quicktemplates/qquickabstractbutton_p.h
+++ b/src/quicktemplates/qquickabstractbutton_p.h
@@ -119,6 +119,8 @@ public:
public Q_SLOTS:
void toggle();
+ Q_REVISION(6, 8) void click();
+ Q_REVISION(6, 8) void animateClick();
Q_SIGNALS:
void pressed();
diff --git a/src/quicktemplates/qquickabstractbutton_p_p.h b/src/quicktemplates/qquickabstractbutton_p_p.h
index ea9a02c99d..0d5eb65940 100644
--- a/src/quicktemplates/qquickabstractbutton_p_p.h
+++ b/src/quicktemplates/qquickabstractbutton_p_p.h
@@ -103,6 +103,7 @@ public:
int repeatTimer = 0;
int repeatDelay = AUTO_REPEAT_DELAY;
int repeatInterval = AUTO_REPEAT_INTERVAL;
+ int animateTimer = 0;
#if QT_CONFIG(shortcut)
int shortcutId = 0;
QKeySequence shortcut;
diff --git a/src/quicktemplates/qquickaction.cpp b/src/quicktemplates/qquickaction.cpp
index 3c28ae98bc..134e7c6f6c 100644
--- a/src/quicktemplates/qquickaction.cpp
+++ b/src/quicktemplates/qquickaction.cpp
@@ -6,6 +6,8 @@
#include "qquickactiongroup_p.h"
#include "qquickshortcutcontext_p_p.h"
+#include <QtCore/qpointer.h>
+#include <QtCore/qloggingcategory.h>
#include <QtGui/qevent.h>
#if QT_CONFIG(shortcut)
# include <QtGui/private/qshortcutmap_p.h>
@@ -13,10 +15,10 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtQuick/private/qquickitem_p.h>
-#include <QtCore/qpointer.h>
-
QT_BEGIN_NAMESPACE
+Q_STATIC_LOGGING_CATEGORY(lcAction, "qt.quick.controls.action")
+
/*!
\qmltype Action
\inherits QtObject
@@ -316,6 +318,7 @@ QQuickAction::QQuickAction(QObject *parent)
QQuickAction::~QQuickAction()
{
Q_D(QQuickAction);
+ qCDebug(lcAction) << "destroying" << this << d->text;
if (d->group)
d->group->removeAction(this);
diff --git a/src/quicktemplates/qquickapplicationwindow.cpp b/src/quicktemplates/qquickapplicationwindow.cpp
index 56e4b5c217..c10eec6bb8 100644
--- a/src/quicktemplates/qquickapplicationwindow.cpp
+++ b/src/quicktemplates/qquickapplicationwindow.cpp
@@ -8,6 +8,7 @@
#include "qquicktextarea_p.h"
#include "qquicktextfield_p.h"
#include "qquicktoolbar_p.h"
+#include "qquicktooltip_p.h"
#include <private/qtquicktemplates2-config_p.h>
#if QT_CONFIG(quicktemplates2_container)
#include "qquicktabbar_p.h"
@@ -104,6 +105,7 @@ public:
QQmlListProperty<QObject> contentData();
+ void updateHasBackgroundFlags();
void relayout();
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
@@ -134,9 +136,15 @@ public:
// Update regular children
QQuickWindowPrivate::updateChildrenPalettes(parentPalette);
- // And cover one special case
- for (auto &&popup : q_func()->findChildren<QQuickPopup *>())
- QQuickPopupPrivate::get(popup)->updateContentPalettes(parentPalette);
+ // And cover special cases
+ for (auto &&child : q_func()->findChildren<QObject *>()) {
+ if (auto *popup = qobject_cast<QQuickPopup *>(child))
+ QQuickPopupPrivate::get(popup)->updateContentPalettes(parentPalette);
+ else if (auto *toolTipAttached = qobject_cast<QQuickToolTipAttached *>(child)) {
+ if (auto *toolTip = toolTipAttached->toolTip())
+ QQuickPopupPrivate::get(toolTip)->updateContentPalettes(parentPalette);
+ }
+ }
}
QQuickDeferredPointer<QQuickItem> background;
@@ -165,6 +173,16 @@ static void layoutItem(QQuickItem *item, qreal y, qreal width)
}
}
+void QQuickApplicationWindowPrivate::updateHasBackgroundFlags()
+{
+ if (!background)
+ return;
+
+ QQuickItemPrivate *backgroundPrivate = QQuickItemPrivate::get(background);
+ hasBackgroundWidth = backgroundPrivate->widthValid();
+ hasBackgroundHeight = backgroundPrivate->heightValid();
+}
+
void QQuickApplicationWindowPrivate::relayout()
{
Q_Q(QQuickApplicationWindow);
@@ -200,9 +218,7 @@ void QQuickApplicationWindowPrivate::itemGeometryChanged(QQuickItem *item, QQuic
if (!insideRelayout && item == background && change.sizeChange()) {
// Any time the background is resized (excluding our own resizing),
// we should respect it if it's explicit by storing the values of the flags.
- QQuickItemPrivate *backgroundPrivate = QQuickItemPrivate::get(background);
- hasBackgroundWidth = backgroundPrivate->widthValid();
- hasBackgroundHeight = backgroundPrivate->heightValid();
+ updateHasBackgroundFlags();
}
relayout();
@@ -297,8 +313,12 @@ void QQuickApplicationWindowPrivate::executeBackground(bool complete)
if (!background || complete)
quickBeginDeferred(q, backgroundName(), background);
- if (complete)
+ if (complete) {
quickCompleteDeferred(q, backgroundName(), background);
+ // See comment in setBackground for why we do this here.
+ updateHasBackgroundFlags();
+ relayout();
+ }
}
QQuickApplicationWindow::QQuickApplicationWindow(QWindow *parent)
@@ -374,12 +394,15 @@ void QQuickApplicationWindow::setBackground(QQuickItem *background)
if (qFuzzyIsNull(background->z()))
background->setZ(-1);
- QQuickItemPrivate *backgroundPrivate = QQuickItemPrivate::get(background);
- d->hasBackgroundWidth = backgroundPrivate->widthValid();
- d->hasBackgroundHeight = backgroundPrivate->heightValid();
+ // If the background hasn't finished executing then we don't know if its width and height
+ // are valid or not, and so relayout would see that they haven't been set yet and override
+ // any bindings the user might have.
+ if (!d->background.isExecuting()) {
+ d->updateHasBackgroundFlags();
- if (isComponentComplete())
- d->relayout();
+ if (isComponentComplete())
+ d->relayout();
+ }
}
if (!d->background.isExecuting())
emit backgroundChanged();
diff --git a/src/quicktemplates/qquickbuttongroup.cpp b/src/quicktemplates/qquickbuttongroup.cpp
index d57b82c8e7..bb5787a3d2 100644
--- a/src/quicktemplates/qquickbuttongroup.cpp
+++ b/src/quicktemplates/qquickbuttongroup.cpp
@@ -102,7 +102,9 @@ QT_BEGIN_NAMESPACE
\code
ButtonGroup {
buttons: column.children
- onClicked: console.log("clicked:", button.text)
+ onClicked: button => {
+ console.log("clicked:", button.text)
+ }
}
Column {
diff --git a/src/quicktemplates/qquickcombobox.cpp b/src/quicktemplates/qquickcombobox.cpp
index c55e988b74..055047a121 100644
--- a/src/quicktemplates/qquickcombobox.cpp
+++ b/src/quicktemplates/qquickcombobox.cpp
@@ -29,7 +29,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcCalculateWidestTextWidth, "qt.quick.controls.combobox.calculatewidesttextwidth")
+Q_STATIC_LOGGING_CATEGORY(lcCalculateWidestTextWidth, "qt.quick.controls.combobox.calculatewidesttextwidth")
/*!
\qmltype ComboBox
diff --git a/src/quicktemplates/qquickcontrol.cpp b/src/quicktemplates/qquickcontrol.cpp
index 72d298d0af..fd29155432 100644
--- a/src/quicktemplates/qquickcontrol.cpp
+++ b/src/quicktemplates/qquickcontrol.cpp
@@ -911,6 +911,19 @@ void QQuickControlPrivate::itemFocusChanged(QQuickItem *item, Qt::FocusReason re
setLastFocusChangeReason(reason);
}
+bool QQuickControlPrivate::setLastFocusChangeReason(Qt::FocusReason reason)
+{
+ Q_Q(QQuickControl);
+ Qt::FocusReason oldReason = static_cast<Qt::FocusReason>(focusReason);
+ const auto focusReasonChanged = QQuickItemPrivate::setLastFocusChangeReason(reason);
+ if (focusReasonChanged)
+ emit q->focusReasonChanged();
+ if (isKeyFocusReason(oldReason) != isKeyFocusReason(reason))
+ emit q->visualFocusChanged();
+
+ return focusReasonChanged;
+}
+
QQuickControl::QQuickControl(QQuickItem *parent)
: QQuickItem(*(new QQuickControlPrivate), parent)
{
@@ -1384,11 +1397,7 @@ Qt::FocusReason QQuickControl::focusReason() const
void QQuickControl::setFocusReason(Qt::FocusReason reason)
{
Q_D(QQuickControl);
- Qt::FocusReason oldReason = static_cast<Qt::FocusReason>(d->focusReason);
d->setLastFocusChangeReason(reason);
- emit focusReasonChanged();
- if (isKeyFocusReason(oldReason) != isKeyFocusReason(reason))
- emit visualFocusChanged();
}
/*!
@@ -1403,7 +1412,7 @@ void QQuickControl::setFocusReason(Qt::FocusReason reason)
\l Item::activeFocus. This ensures that key focus is only visualized when
interacting with keys - not when interacting via touch or mouse.
- \sa Item::focusReason, Item::activeFocus
+ \sa focusReason, Item::activeFocus
*/
bool QQuickControl::hasVisualFocus() const
{
@@ -1448,7 +1457,7 @@ void QQuickControl::setHovered(bool hovered)
\qmlproperty bool QtQuick.Controls::Control::hoverEnabled
This property determines whether the control accepts hover events. The default value
- is \c Qt.styleHints.useHoverEffects.
+ is \c Application.styleHints.useHoverEffects.
Setting this property propagates the value to all child controls that do not have
\c hoverEnabled explicitly set.
@@ -1969,22 +1978,12 @@ QFont QQuickControl::defaultFont() const
void QQuickControl::focusInEvent(QFocusEvent *event)
{
- Q_D(QQuickControl);
- Qt::FocusReason oldReason = static_cast<Qt::FocusReason>(d->focusReason);
QQuickItem::focusInEvent(event);
- Qt::FocusReason reason = event->reason();
- if (isKeyFocusReason(oldReason) != isKeyFocusReason(reason))
- emit visualFocusChanged();
}
void QQuickControl::focusOutEvent(QFocusEvent *event)
{
- Q_D(QQuickControl);
- Qt::FocusReason oldReason = static_cast<Qt::FocusReason>(d->focusReason);
QQuickItem::focusOutEvent(event);
- Qt::FocusReason reason = event->reason();
- if (isKeyFocusReason(oldReason) != isKeyFocusReason(reason))
- emit visualFocusChanged();
}
#if QT_CONFIG(quicktemplates2_hover)
diff --git a/src/quicktemplates/qquickcontrol_p_p.h b/src/quicktemplates/qquickcontrol_p_p.h
index c58ee33ede..24d0507670 100644
--- a/src/quicktemplates/qquickcontrol_p_p.h
+++ b/src/quicktemplates/qquickcontrol_p_p.h
@@ -155,6 +155,8 @@ public:
void itemDestroyed(QQuickItem *item) override;
void itemFocusChanged(QQuickItem *item, Qt::FocusReason reason) override;
+ bool setLastFocusChangeReason(Qt::FocusReason) override;
+
virtual qreal getContentWidth() const;
virtual qreal getContentHeight() const;
diff --git a/src/quicktemplates/qquickdialog.cpp b/src/quicktemplates/qquickdialog.cpp
index 30daee5f33..7a1c5d513b 100644
--- a/src/quicktemplates/qquickdialog.cpp
+++ b/src/quicktemplates/qquickdialog.cpp
@@ -6,6 +6,7 @@
#include "qquickdialogbuttonbox_p.h"
#include "qquickabstractbutton_p.h"
#include "qquickpopupitem_p_p.h"
+#include "qquickpopupwindow_p_p.h"
QT_BEGIN_NAMESPACE
@@ -164,6 +165,11 @@ void QQuickDialogPrivate::handleClick(QQuickAbstractButton *button)
}
}
+Qt::WindowFlags QQuickDialogPrivate::popupWindowType() const
+{
+ return Qt::Dialog;
+}
+
QQuickDialog::QQuickDialog(QObject *parent)
: QQuickDialog(*(new QQuickDialogPrivate), parent)
{
@@ -176,8 +182,6 @@ QQuickDialog::QQuickDialog(QQuickDialogPrivate &dd, QObject *parent)
// Dialogs should get active focus when opened so that e.g. Cancel closes them.
setFocus(true);
-
- QObject::connect(d->popupItem, &QQuickPopupItem::titleChanged, this, &QQuickDialog::titleChanged);
QObject::connect(d->popupItem, &QQuickPopupItem::headerChanged, this, &QQuickDialog::headerChanged);
QObject::connect(d->popupItem, &QQuickPopupItem::footerChanged, this, &QQuickDialog::footerChanged);
QObject::connect(d->popupItem, &QQuickPopupItem::implicitHeaderWidthChanged, this, &QQuickDialog::implicitHeaderWidthChanged);
@@ -189,7 +193,6 @@ QQuickDialog::QQuickDialog(QQuickDialogPrivate &dd, QObject *parent)
QQuickDialog::~QQuickDialog()
{
Q_D(QQuickDialog);
- QObject::disconnect(d->popupItem, &QQuickPopupItem::titleChanged, this, &QQuickDialog::titleChanged);
QObject::disconnect(d->popupItem, &QQuickPopupItem::headerChanged, this, &QQuickDialog::headerChanged);
QObject::disconnect(d->popupItem, &QQuickPopupItem::footerChanged, this, &QQuickDialog::footerChanged);
QObject::disconnect(d->popupItem, &QQuickPopupItem::implicitHeaderWidthChanged, this, &QQuickDialog::implicitHeaderWidthChanged);
@@ -218,13 +221,22 @@ QQuickDialog::~QQuickDialog()
QString QQuickDialog::title() const
{
Q_D(const QQuickDialog);
- return d->popupItem->title();
+ return d->m_title;
}
void QQuickDialog::setTitle(const QString &title)
{
Q_D(QQuickDialog);
- d->popupItem->setTitle(title);
+ if (d->m_title == title)
+ return;
+ d->m_title = title;
+
+ if (d->popupWindow)
+ d->popupWindow->setTitle(title);
+ else
+ d->popupItem->setTitle(title);
+
+ emit titleChanged();
}
/*!
@@ -488,6 +500,12 @@ qreal QQuickDialog::implicitFooterHeight() const
return d->popupItem->implicitFooterHeight();
}
+void QQuickDialog::setOpacity(qreal opacity)
+{
+ Q_D(QQuickDialog);
+ QQuickPopup::setOpacity(d->popupWindow ? qreal(!qFuzzyIsNull(opacity)) : opacity);
+}
+
/*!
\qmlmethod void QtQuick.Controls::Dialog::accept()
diff --git a/src/quicktemplates/qquickdialog_p.h b/src/quicktemplates/qquickdialog_p.h
index 63fac39f97..0c549127a9 100644
--- a/src/quicktemplates/qquickdialog_p.h
+++ b/src/quicktemplates/qquickdialog_p.h
@@ -74,6 +74,8 @@ public:
qreal implicitFooterWidth() const;
qreal implicitFooterHeight() const;
+ void setOpacity(qreal opacity) override;
+
public Q_SLOTS:
virtual void accept();
virtual void reject();
@@ -111,6 +113,31 @@ private:
Q_DECLARE_PRIVATE(QQuickDialog)
};
+// The dialog options are registered here because they conceptually belong to QPlatformDialogHelper
+// used as extension above. They may not be used QtQuick.Templates itself, but not registering them
+// here would cause every downstream module that uses them to produce a redundant registration.
+
+struct QColorDialogOptionsForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN_NAMESPACE(QColorDialogOptions)
+};
+
+struct QFileDialogOptionsForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN_NAMESPACE(QFileDialogOptions)
+};
+
+struct QFontDialogOptionsForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN_NAMESPACE(QFontDialogOptions)
+};
+
QT_END_NAMESPACE
#endif // QQUICKDIALOG_P_H
diff --git a/src/quicktemplates/qquickdialog_p_p.h b/src/quicktemplates/qquickdialog_p_p.h
index dd4c3fa1f0..9b0e5d177a 100644
--- a/src/quicktemplates/qquickdialog_p_p.h
+++ b/src/quicktemplates/qquickdialog_p_p.h
@@ -40,6 +40,8 @@ public:
virtual void handleReject();
virtual void handleClick(QQuickAbstractButton *button);
+ Qt::WindowFlags popupWindowType() const override;
+
int result = 0;
QString title;
QQuickDialogButtonBox *buttonBox = nullptr;
diff --git a/src/quicktemplates/qquickdrawer.cpp b/src/quicktemplates/qquickdrawer.cpp
index f67a8ec76a..b3d8ef3fc8 100644
--- a/src/quicktemplates/qquickdrawer.cpp
+++ b/src/quicktemplates/qquickdrawer.cpp
@@ -596,6 +596,12 @@ bool QQuickDrawerPrivate::prepareExitTransition()
return QQuickPopupPrivate::prepareExitTransition();
}
+QQuickPopup::PopupType QQuickDrawerPrivate::resolvedPopupType() const
+{
+ // For now, a drawer will always be shown in-scene
+ return QQuickPopup::Item;
+}
+
bool QQuickDrawerPrivate::setEdge(Qt::Edge e)
{
Q_Q(QQuickDrawer);
@@ -728,7 +734,7 @@ void QQuickDrawer::setPosition(qreal position)
drag actions will open the drawer. Setting the value to \c 0 or less
prevents opening the drawer by dragging.
- The default value is \c Qt.styleHints.startDragDistance.
+ The default value is \c Application.styleHints.startDragDistance.
\sa interactive
*/
diff --git a/src/quicktemplates/qquickdrawer_p_p.h b/src/quicktemplates/qquickdrawer_p_p.h
index 7eae26b0cb..18646463b5 100644
--- a/src/quicktemplates/qquickdrawer_p_p.h
+++ b/src/quicktemplates/qquickdrawer_p_p.h
@@ -54,6 +54,8 @@ public:
bool prepareEnterTransition() override;
bool prepareExitTransition() override;
+ QQuickPopup::PopupType resolvedPopupType() const override;
+
bool setEdge(Qt::Edge edge);
Qt::Edge effectiveEdge() const;
bool isWithinDragMargin(const QPointF &point) const;
diff --git a/src/quicktemplates/qquickheaderview.cpp b/src/quicktemplates/qquickheaderview.cpp
index b94280865f..dedf3a23e1 100644
--- a/src/quicktemplates/qquickheaderview.cpp
+++ b/src/quicktemplates/qquickheaderview.cpp
@@ -64,6 +64,20 @@
\include qquickheaderview.qdocinc {textRole}
*/
+/*!
+ \qmlproperty bool QtQuick.Controls::HorizontalHeaderView::movableColumns
+ \since 6.8
+
+ \include qquickheaderview.qdocinc {movableColumns}
+*/
+
+/*!
+ \qmlproperty bool QtQuick.Controls::VerticalHeaderView::movableRows
+ \since 6.8
+
+ \include qquickheaderview.qdocinc {movableRows}
+*/
+
QT_BEGIN_NAMESPACE
QQuickHeaderViewBasePrivate::QQuickHeaderViewBasePrivate()
@@ -173,6 +187,26 @@ QAbstractItemModel *QQuickHeaderViewBasePrivate::selectionSourceModel()
return &m_headerDataProxyModel;
}
+int QQuickHeaderViewBasePrivate::logicalRowIndex(const int visualIndex) const
+{
+ return (m_headerDataProxyModel.orientation() == Qt::Horizontal) ? visualIndex : QQuickTableViewPrivate::logicalRowIndex(visualIndex);
+}
+
+int QQuickHeaderViewBasePrivate::logicalColumnIndex(const int visualIndex) const
+{
+ return (m_headerDataProxyModel.orientation() == Qt::Vertical) ? visualIndex : QQuickTableViewPrivate::logicalColumnIndex(visualIndex);
+}
+
+int QQuickHeaderViewBasePrivate::visualRowIndex(const int logicalIndex) const
+{
+ return (m_headerDataProxyModel.orientation() == Qt::Horizontal) ? logicalIndex : QQuickTableViewPrivate::visualRowIndex(logicalIndex);
+}
+
+int QQuickHeaderViewBasePrivate::visualColumnIndex(const int logicalIndex) const
+{
+ return (m_headerDataProxyModel.orientation() == Qt::Vertical) ? logicalIndex : QQuickTableViewPrivate::visualColumnIndex(logicalIndex);
+}
+
QQuickHeaderViewBase::QQuickHeaderViewBase(Qt::Orientation orient, QQuickItem *parent)
: QQuickTableView(*(new QQuickHeaderViewBasePrivate), parent)
{
@@ -415,6 +449,30 @@ QQuickHorizontalHeaderView::QQuickHorizontalHeaderView(QQuickItem *parent)
QQuickHorizontalHeaderView::~QQuickHorizontalHeaderView()
{
+ Q_D(QQuickHorizontalHeaderView);
+ d->destroySectionDragHandler();
+}
+
+bool QQuickHorizontalHeaderView::movableColumns() const
+{
+ Q_D(const QQuickHorizontalHeaderView);
+ return d->m_movableColumns;
+}
+
+void QQuickHorizontalHeaderView::setMovableColumns(bool movableColumns)
+{
+ Q_D(QQuickHorizontalHeaderView);
+ if (d->m_movableColumns == movableColumns)
+ return;
+
+ d->m_movableColumns = movableColumns;
+
+ if (d->m_movableColumns)
+ d->initSectionDragHandler(Qt::Horizontal);
+ else
+ d->destroySectionDragHandler();
+
+ emit movableColumnsChanged();
}
QQuickVerticalHeaderView::QQuickVerticalHeaderView(QQuickItem *parent)
@@ -426,6 +484,30 @@ QQuickVerticalHeaderView::QQuickVerticalHeaderView(QQuickItem *parent)
QQuickVerticalHeaderView::~QQuickVerticalHeaderView()
{
+ Q_D(QQuickVerticalHeaderView);
+ d->destroySectionDragHandler();
+}
+
+bool QQuickVerticalHeaderView::movableRows() const
+{
+ Q_D(const QQuickVerticalHeaderView);
+ return d->m_movableRows ;
+}
+
+void QQuickVerticalHeaderView::setMovableRows(bool movableRows)
+{
+ Q_D(QQuickVerticalHeaderView);
+ if (d->m_movableRows == movableRows)
+ return;
+
+ d->m_movableRows = movableRows;
+
+ if (d->m_movableRows)
+ d->initSectionDragHandler(Qt::Vertical);
+ else
+ d->destroySectionDragHandler();
+
+ emit movableRowsChanged();
}
QQuickHorizontalHeaderViewPrivate::QQuickHorizontalHeaderViewPrivate() = default;
diff --git a/src/quicktemplates/qquickheaderview_p.h b/src/quicktemplates/qquickheaderview_p.h
index 5280f563dc..ba123a3c3e 100644
--- a/src/quicktemplates/qquickheaderview_p.h
+++ b/src/quicktemplates/qquickheaderview_p.h
@@ -52,6 +52,7 @@ class Q_QUICKTEMPLATES2_EXPORT QQuickHorizontalHeaderView : public QQuickHeaderV
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickHorizontalHeaderView)
+ Q_PROPERTY(bool movableColumns READ movableColumns WRITE setMovableColumns NOTIFY movableColumnsChanged REVISION(6, 8) FINAL)
QML_NAMED_ELEMENT(HorizontalHeaderView)
QML_ADDED_IN_VERSION(2, 15)
@@ -59,6 +60,12 @@ public:
QQuickHorizontalHeaderView(QQuickItem *parent = nullptr);
~QQuickHorizontalHeaderView() override;
+ bool movableColumns() const;
+ void setMovableColumns(bool movableColumns);
+
+Q_SIGNALS:
+ Q_REVISION(6, 8) void movableColumnsChanged();
+
protected:
QQuickHorizontalHeaderView(QQuickHorizontalHeaderViewPrivate &dd, QQuickItem *parent);
@@ -71,6 +78,7 @@ class Q_QUICKTEMPLATES2_EXPORT QQuickVerticalHeaderView : public QQuickHeaderVie
{
Q_OBJECT
Q_DECLARE_PRIVATE(QQuickVerticalHeaderView)
+ Q_PROPERTY(bool movableRows READ movableRows WRITE setMovableRows NOTIFY movableRowsChanged REVISION(6, 8) FINAL)
QML_NAMED_ELEMENT(VerticalHeaderView)
QML_ADDED_IN_VERSION(2, 15)
@@ -78,6 +86,12 @@ public:
QQuickVerticalHeaderView(QQuickItem *parent = nullptr);
~QQuickVerticalHeaderView() override;
+ bool movableRows() const;
+ void setMovableRows(bool movableRows);
+
+Q_SIGNALS:
+ Q_REVISION(6, 8) void movableRowsChanged();
+
protected:
QQuickVerticalHeaderView(QQuickVerticalHeaderViewPrivate &dd, QQuickItem *parent);
diff --git a/src/quicktemplates/qquickheaderview_p_p.h b/src/quicktemplates/qquickheaderview_p_p.h
index 4269d1c1a0..63abd58aa3 100644
--- a/src/quicktemplates/qquickheaderview_p_p.h
+++ b/src/quicktemplates/qquickheaderview_p_p.h
@@ -88,6 +88,11 @@ protected:
QStack<SectionSize> m_hiddenSectionSizes;
bool m_modelExplicitlySetByUser = false;
QString m_textRole;
+
+ int logicalRowIndex(const int visualIndex) const final;
+ int logicalColumnIndex(const int visualIndex) const final;
+ int visualRowIndex(const int logicalIndex) const final;
+ int visualColumnIndex(const int logicalIndex) const final;
};
class QQuickHorizontalHeaderViewPrivate : public QQuickHeaderViewBasePrivate
@@ -96,6 +101,8 @@ class QQuickHorizontalHeaderViewPrivate : public QQuickHeaderViewBasePrivate
public:
QQuickHorizontalHeaderViewPrivate();
~QQuickHorizontalHeaderViewPrivate();
+
+ bool m_movableColumns = false;
};
class QQuickVerticalHeaderViewPrivate : public QQuickHeaderViewBasePrivate
@@ -104,6 +111,8 @@ class QQuickVerticalHeaderViewPrivate : public QQuickHeaderViewBasePrivate
public:
QQuickVerticalHeaderViewPrivate();
~QQuickVerticalHeaderViewPrivate();
+
+ bool m_movableRows = false;
};
QT_END_NAMESPACE
diff --git a/src/quicktemplates/qquickmenu.cpp b/src/quicktemplates/qquickmenu.cpp
index 707b115983..0f4c557952 100644
--- a/src/quicktemplates/qquickmenu.cpp
+++ b/src/quicktemplates/qquickmenu.cpp
@@ -7,18 +7,23 @@
#include <private/qtquicktemplates2-config_p.h>
#if QT_CONFIG(quicktemplates2_container)
#include "qquickmenubaritem_p.h"
-#include "qquickmenubar_p.h"
+#include "qquickmenubar_p_p.h"
#endif
+#include "qquickmenuseparator_p.h"
+#include "qquicknativemenuitem_p.h"
#include "qquickpopupitem_p_p.h"
#include "qquickpopuppositioner_p_p.h"
#include "qquickaction_p.h"
+#include <QtCore/qloggingcategory.h>
#include <QtGui/qevent.h>
#include <QtGui/qcursor.h>
#if QT_CONFIG(shortcut)
#include <QtGui/qkeysequence.h>
#endif
#include <QtGui/qpa/qplatformintegration.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlcomponent.h>
@@ -30,10 +35,15 @@
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickitemchangelistener_p.h>
#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuick/private/qquicklistview_p.h>
+#include <QtQuick/private/qquickrendercontrol_p.h>
#include <QtQuick/private/qquickwindow_p.h>
QT_BEGIN_NAMESPACE
+Q_STATIC_LOGGING_CATEGORY(lcMenu, "qt.quick.controls.menu")
+Q_STATIC_LOGGING_CATEGORY(lcNativeMenus, "qt.quick.controls.nativemenus")
+
// copied from qfusionstyle.cpp
static const int SUBMENU_DELAY = 225;
@@ -47,7 +57,13 @@ static const int SUBMENU_DELAY = 225;
\ingroup qtquickcontrols-popups
\brief Menu popup that can be used as a context menu or popup menu.
- \image qtquickcontrols-menu.png
+ \table
+ \row
+ \li \image qtquickcontrols-menu-native.png
+ \caption Native macOS menu.
+ \li \image qtquickcontrols-menu.png
+ \caption Non-native \l {Material Style}{Material style} menu.
+ \endtable
Menu has two main use cases:
\list
@@ -184,6 +200,82 @@ static const int SUBMENU_DELAY = 225;
\sa {Customizing Menu}, MenuItem, {Menu Controls}, {Popup Controls},
{Dynamic QML Object Creation from JavaScript}
+
+ \section1 Menu types
+
+ Since Qt 6.8, a menu offers three different implementations, depending on the
+ platform. You can choose which one should be preferred by setting
+ \l popupType. This will let you control if a menu should be shown as a separate
+ window, as an item inside the parent window, or as a native menu. You can read
+ more about these options \l{Popup type}{here.}
+
+ Whether a menu will be able to use the preferred type depends on the platform.
+ \c Popup.Item is supported on all platforms, but \c Popup.Window and \c Popup.Native
+ are normally only supported on desktop platforms. Additionally, if the menu is inside
+ a \l {Native menu bars}{native menubar}, the menu will be native as well. And if
+ the menu is a sub-menu inside another menu, the parent (or root) menu will decide the type.
+
+ \section2 Limitations when using native menus
+
+ When setting \l popupType to \c Popup.Native, there are some limitations and
+ differences compared to using \c Popup.Item and \c Popup.Window.
+
+ \section3 API differences
+
+ When using native menus, only a subset of the Menu API is supported on all platforms:
+
+ \list
+ \li \l {Popup::}{x}
+ \li \l {Popup::}{y}
+ \li \l {Popup::}{visible}
+ \li \l {Popup::}{opened}
+ \li \l title
+ \li \l count
+ \li \l {Popup::}{contentData}
+ \li \l {Popup::}{contentChildren} (visual children will not be visible)
+ \li \l contentModel
+ \li \l {Popup::}{open()}
+ \li \l {Popup::}{popup()}
+ \li \l {Popup::}{close()}
+ \li \l {Popup::}{opened()}
+ \li \l {Popup::}{closed()}
+ \li \l {Popup::}{aboutToShow()}
+ \li \l {Popup::}{aboutToHide()}
+ \endlist
+
+ In addition, showing a popup (using for example \l {Popup::}{open()} or \l {Popup::}{popup()}
+ will, on some platforms, be a blocking call. This means that the call will not return
+ before the menu is closed again, which can affect the logic in your application. This is
+ especially important to take into consideration if your application is targeting multiple
+ platforms, and as such, sometimes run on platforms where native menus are not supported.
+ In that case the popupType will fall back to \c Popup.Item, for example, and calls to
+ \l {Popup::}{open()} will not be blocking.
+
+ Items like \l MenuItem will still react to clicks in the corresponding
+ native menu item by emitting signals, for example, but will be replaced by
+ their native counterpart.
+
+ \section3 Rendering differences
+
+ Native menus are implemented using the available native menu APIs on the platform.
+ Those menus, and all of their contents, will therefore be rendered by the platform, and
+ not by QML. This means that the \l delegate will \e not be used for rendering. It will,
+ however, always be instantiated (but hidden), so that functions such as
+ \l {Component.onCompleted()} execute regardless of platform and \l popupType.
+
+ \section3 Supported platforms
+
+ Native menus are currently supported on the following platforms:
+
+ \list
+ \li Android
+ \li iOS
+ \li Linux (only available as a stand-alone context menu when running with the GTK+ platform theme)
+ \li macOS
+ \li Windows
+ \endlist
+
+ \sa {Popup type}, popupType
*/
/*!
@@ -197,6 +289,8 @@ static const int SUBMENU_DELAY = 225;
The default value is \c true.
+ \include qquickmenu.qdocinc non-native-only-property
+
\sa {Popup::}{activeFocus}
*/
@@ -230,6 +324,303 @@ void QQuickMenuPrivate::init()
contentModel = new QQmlObjectModel(q);
}
+QQuickMenu *QQuickMenuPrivate::rootMenu() const
+{
+ Q_Q(const QQuickMenu);
+ const QQuickMenu *rootMenu = q;
+ const QObject *p = q->parent();
+ while (p) {
+ if (auto menu = qobject_cast<const QQuickMenu *>(p))
+ rootMenu = menu;
+ p = p->parent();
+ }
+
+ return const_cast<QQuickMenu *>(rootMenu);
+}
+
+ QQuickPopup::PopupType QQuickMenuPrivate::resolvedPopupType() const
+{
+ // The resolved popup type is decided by the root
+ // menu (which can be this menu, unless it's a child menu).
+ QQuickMenuPrivate *root_d = QQuickMenuPrivate::get(rootMenu());
+
+ // If the root menu is native, then so should we. We assume here that
+ // the root menu is always shown and created first, before we try to
+ // show and create a child menu.
+ if (root_d->maybeNativeHandle())
+ return QQuickPopup::PopupType::Native;
+
+ return root_d->QQuickPopupPrivate::resolvedPopupType();
+}
+
+bool QQuickMenuPrivate::useNativeMenu() const
+{
+ // If we're inside a MenuBar, it'll decide whether or not we
+ // should be native or not. Otherwise, the root menu (which
+ // might be this menu) will decide.
+ QQuickMenu *root = rootMenu();
+ if (auto menuBar = QQuickMenuPrivate::get(root)->menuBar.get())
+ return QQuickMenuBarPrivate::get(menuBar)->useNativeMenu(q_func());
+ return root->popupType() == QQuickPopup::Native;
+}
+
+QPlatformMenu *QQuickMenuPrivate::nativeHandle()
+{
+ Q_ASSERT(handle || useNativeMenu());
+ if (!handle && !triedToCreateNativeMenu)
+ createNativeMenu();
+ return handle.get();
+}
+
+QPlatformMenu *QQuickMenuPrivate::maybeNativeHandle() const
+{
+ return handle.get();
+}
+
+bool QQuickMenuPrivate::createNativeMenu()
+{
+ Q_ASSERT(!handle);
+ Q_Q(QQuickMenu);
+ qCDebug(lcNativeMenus) << "createNativeMenu called on" << q;
+
+ if (auto menuBar = QQuickMenuPrivate::get(rootMenu())->menuBar) {
+ auto menuBarPrivate = QQuickMenuBarPrivate::get(menuBar);
+ if (menuBarPrivate->useNativeMenuBar()) {
+ qCDebug(lcNativeMenus) << "- creating native menu from native menubar";
+ if (QPlatformMenuBar *menuBarHandle = menuBarPrivate->nativeHandle())
+ handle.reset(menuBarHandle->createMenu());
+ }
+ }
+
+ if (!handle) {
+ QPlatformMenu *parentMenuHandle(parentMenu ? get(parentMenu)->handle.get() : nullptr);
+ if (parentMenu && parentMenuHandle) {
+ qCDebug(lcNativeMenus) << "- creating native sub-menu";
+ handle.reset(parentMenuHandle->createSubMenu());
+ } else {
+ qCDebug(lcNativeMenus) << "- creating native menu";
+ handle.reset(QGuiApplicationPrivate::platformTheme()->createPlatformMenu());
+ }
+ }
+
+ triedToCreateNativeMenu = true;
+
+ if (!handle)
+ return false;
+
+ q->connect(handle.get(), &QPlatformMenu::aboutToShow, q, [q, this](){
+ emit q->aboutToShow();
+ visible = true;
+ emit q->visibleChanged();
+ emit q->openedChanged();
+ opened();
+ });
+ q->connect(handle.get(), &QPlatformMenu::aboutToHide, q, [q, this](){
+ qCDebug(lcNativeMenus) << "QPlatformMenu::aboutToHide called; about to call setVisible(false) on Menu";
+ emit q->aboutToHide();
+ visible = false;
+ emit q->visibleChanged();
+ emit q->openedChanged();
+ emit q->closed();
+ });
+
+ recursivelyCreateNativeMenuItems(q);
+ syncWithNativeMenu();
+
+ return true;
+}
+
+QString nativeMenuItemListToString(const QList<QQuickNativeMenuItem *> &nativeItems)
+{
+ if (nativeItems.isEmpty())
+ return QStringLiteral("(Empty)");
+
+ QString str;
+ QTextStream debug(&str);
+ for (const auto *nativeItem : nativeItems)
+ debug << nativeItem->debugText() << ", ";
+ // Remove trailing space and comma.
+ if (!nativeItems.isEmpty())
+ str.chop(2);
+ return str;
+}
+
+void QQuickMenuPrivate::syncWithNativeMenu()
+{
+ Q_Q(QQuickMenu);
+ if (!complete || !handle)
+ return;
+
+ qCDebug(lcNativeMenus).nospace() << "syncWithNativeMenu called on " << q
+ << " (complete: " << complete << " visible: " << visible << ") - "
+ << "syncing " << nativeItems.size() << " item(s)...";
+
+ // TODO: call this function when any of the variables below change
+
+ handle->setText(title);
+ handle->setEnabled(q->isEnabled());
+ handle->setMinimumWidth(q->implicitWidth());
+// nativeHandle->setMenuType(m_type);
+ handle->setFont(q->font());
+
+ // Note: the QQuickMenu::visible property is used to open or close the menu.
+ // This is in contrast to QPlatformMenu::visible, which tells if the menu
+ // should be visible in the menubar or not (if it belongs to one). To control
+ // if a QPlatformMenu should be open, we instead use QPlatformMenu::showPopup()
+ // and dismiss(). As such, we don't want to call handle->setVisible(visible)
+ // from this function since we always want the menu to be visible in the menubar
+ // (if it belongs to one). The currently only way to hide a menu from a menubar is
+ // to instead call MenuBar.removeMenu(menu).
+
+// if (m_menuBar && m_menuBar->handle())
+// m_menuBar->handle()->syncMenu(handle);
+//#if QT_CONFIG(systemtrayicon)
+// else if (m_systemTrayIcon && m_systemTrayIcon->handle())
+// m_systemTrayIcon->handle()->updateMenu(handle);
+//#endif
+
+ for (QQuickNativeMenuItem *item : std::as_const(nativeItems)) {
+ qCDebug(lcNativeMenus) << "- syncing" << item << "action" << item->action()
+ << "sub-menu" << item->subMenu() << item->debugText();
+ item->sync();
+ }
+
+ qCDebug(lcNativeMenus) << "... finished syncing" << q;
+}
+
+void QQuickMenuPrivate::removeNativeMenu()
+{
+ // Remove the native menu, including it's native menu items
+ Q_Q(QQuickMenu);
+ const int qtyItemsToRemove = nativeItems.size();
+ if (qtyItemsToRemove != 0)
+ Q_ASSERT(q->count() == qtyItemsToRemove);
+ for (int i = 0; i < qtyItemsToRemove; ++i)
+ removeNativeItem(0);
+ Q_ASSERT(nativeItems.isEmpty());
+
+ // removeNativeItem will take care of destroying sub-menus and resetting their native data,
+ // but as the root menu, we have to take care of our own.
+ resetNativeData();
+}
+
+void QQuickMenuPrivate::syncWithUseNativeMenu()
+{
+ Q_Q(QQuickMenu);
+ // Users can change AA_DontUseNativeMenuWindows while a menu is visible,
+ // but the changes won't take affect until the menu is re-opened.
+ if (q->isVisible() || parentMenu)
+ return;
+
+ if (maybeNativeHandle() && !useNativeMenu()) {
+ // Switch to a non-native menu by removing the native menu and its native items.
+ // Note that there's nothing to do if a native menu was requested but we failed to create it.
+ removeNativeMenu();
+ } else if (useNativeMenu()) {
+ Q_ASSERT(nativeItems.isEmpty());
+ // Try to create a native menu.
+ nativeHandle();
+ }
+}
+
+/*!
+ \internal
+
+ Recursively destroys native sub-menus of \a menu.
+
+ This function checks if each native item in \c menu has a sub-menu,
+ and if so:
+ \list
+ \li Calls itself with that sub-menu
+ \li Resets the item's data (important to avoid accessing a deleted QQuickAction
+ when printing in QQuickNativeMenuItem's destructor)
+ \li Deletes (eventually) the native item
+ \endlist
+
+ Similar (besides the recursion) to removeNativeItem(), except that
+ we can avoid repeated calls to syncWithNativeMenu().
+*/
+void QQuickMenuPrivate::recursivelyDestroyNativeSubMenus(QQuickMenu *menu)
+{
+ auto *menuPrivate = QQuickMenuPrivate::get(menu);
+ Q_ASSERT(menuPrivate->handle);
+ qCDebug(lcNativeMenus) << "recursivelyDestroyNativeSubMenus called with" << menu << "...";
+
+ while (!menuPrivate->nativeItems.isEmpty()) {
+ std::unique_ptr<QQuickNativeMenuItem> item(menuPrivate->nativeItems.takeFirst());
+ qCDebug(lcNativeMenus) << "- taking and destroying" << item->debugText();
+ if (QQuickMenu *subMenu = item->subMenu())
+ recursivelyDestroyNativeSubMenus(subMenu);
+
+ if (item->handle())
+ menuPrivate->handle->removeMenuItem(item->handle());
+ }
+
+ menuPrivate->resetNativeData();
+
+ qCDebug(lcNativeMenus) << "... finished destroying native sub-menus of" << menu;
+}
+
+static QWindow *effectiveWindow(QWindow *window, QPoint *offset)
+{
+ QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(window);
+ if (quickWindow) {
+ QWindow *renderWindow = QQuickRenderControl::renderWindowFor(quickWindow, offset);
+ if (renderWindow)
+ return renderWindow;
+ }
+ return window;
+}
+
+void QQuickMenuPrivate::setNativeMenuVisible(bool visible)
+{
+ Q_Q(QQuickMenu);
+ qCDebug(lcNativeMenus) << "setNativeMenuVisible called with visible" << visible;
+ if (visible)
+ emit q->aboutToShow();
+ else
+ emit q->aboutToHide();
+
+ this->visible = visible;
+ syncWithNativeMenu();
+
+ QPoint offset;
+ QWindow *window = effectiveWindow(qGuiApp->topLevelWindows().first(), &offset);
+
+ if (visible) {
+ lastDevicePixelRatio = window->devicePixelRatio();
+
+ const QPointF globalPos = parentItem->mapToGlobal(x, y);
+ const QPoint windowPos = window->mapFromGlobal(globalPos.toPoint());
+ QRect targetRect(windowPos, QSize(0, 0));
+ auto *daPriv = QQuickItemPrivate::get(parentItem)->deliveryAgentPrivate();
+ Q_ASSERT(daPriv);
+ // A menu is typically opened when some event-handling object (like TapHandler) calls
+ // QQuickMenu::popup(). We don't have the event or the caller available directly here.
+ // But showPopup() below is expected to "eat" the release event, so
+ // the caller will not see it. Cancel all grabs so that the object that
+ // handled the press event will not get stuck in pressed state.
+ if (QPointerEvent *openingEvent = daPriv->eventInDelivery()) {
+ auto *devPriv = QPointingDevicePrivate::get(const_cast<QPointingDevice *>(openingEvent->pointingDevice()));
+ for (const auto &pt : std::as_const(openingEvent->points())) {
+ qCDebug(lcNativeMenus) << "popup over" << window << "its DA" << daPriv->q_func() << "opening due to" << openingEvent
+ << "with grabbers" << openingEvent->exclusiveGrabber(pt) << openingEvent->passiveGrabbers(pt);
+
+ if (auto *opener = openingEvent->exclusiveGrabber(pt))
+ devPriv->removeGrabber(opener, true); // cancel
+ for (auto passiveGrabber : openingEvent->passiveGrabbers(pt)) {
+ if (auto *opener = passiveGrabber.get())
+ devPriv->removeGrabber(opener, true); // cancel
+ }
+ }
+ }
+ handle->showPopup(window, QHighDpi::toNativePixels(targetRect, window),
+ /*menuItem ? menuItem->handle() : */nullptr);
+ } else {
+ handle->dismiss();
+ }
+}
+
QQuickItem *QQuickMenuPrivate::itemAt(int index) const
{
return qobject_cast<QQuickItem *>(contentModel->get(index));
@@ -237,6 +628,9 @@ QQuickItem *QQuickMenuPrivate::itemAt(int index) const
void QQuickMenuPrivate::insertItem(int index, QQuickItem *item)
{
+ qCDebug(lcMenu) << "insert called with index" << index << "item" << item;
+
+ Q_Q(QQuickMenu);
contentData.append(item);
item->setParentItem(contentItem);
QQuickItemPrivate::get(item)->setCulled(true); // QTBUG-53262
@@ -248,23 +642,90 @@ void QQuickMenuPrivate::insertItem(int index, QQuickItem *item)
QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
if (menuItem) {
- Q_Q(QQuickMenu);
QQuickMenuItemPrivate::get(menuItem)->setMenu(q);
if (QQuickMenu *subMenu = menuItem->subMenu())
QQuickMenuPrivate::get(subMenu)->setParentMenu(q);
QObjectPrivate::connect(menuItem, &QQuickMenuItem::triggered, this, &QQuickMenuPrivate::onItemTriggered);
+ QObjectPrivate::connect(menuItem, &QQuickMenuItem::implicitTextPaddingChanged, this, &QQuickMenuPrivate::updateTextPadding);
+ QObjectPrivate::connect(menuItem, &QQuickMenuItem::visibleChanged, this, &QQuickMenuPrivate::updateTextPadding);
QObjectPrivate::connect(menuItem, &QQuickItem::activeFocusChanged, this, &QQuickMenuPrivate::onItemActiveFocusChanged);
QObjectPrivate::connect(menuItem, &QQuickControl::hoveredChanged, this, &QQuickMenuPrivate::onItemHovered);
}
+
+ if (maybeNativeHandle() && complete)
+ maybeCreateAndInsertNativeItem(index, item);
+
+ if (lcMenu().isDebugEnabled())
+ printContentModelItems();
+
+ updateTextPadding();
+}
+
+void QQuickMenuPrivate::maybeCreateAndInsertNativeItem(int index, QQuickItem *item)
+{
+ Q_Q(QQuickMenu);
+ Q_ASSERT(complete);
+ Q_ASSERT_X(handle, Q_FUNC_INFO, qPrintable(QString::fromLatin1(
+ "Expected %1 to be using a native menu").arg(QDebug::toString(q))));
+ std::unique_ptr<QQuickNativeMenuItem> nativeMenuItem(QQuickNativeMenuItem::createFromNonNativeItem(q, item));
+ if (!nativeMenuItem) {
+ // TODO: fall back to non-native menu
+ qmlWarning(q) << "Native menu failed to create a native menu item for item at index" << index;
+ return;
+ }
+
+ nativeItems.insert(index, nativeMenuItem.get());
+
+ // Having a QQuickNativeMenuItem doesn't mean that we were able to create a native handle:
+ // it could be e.g. a Rectangle. See comment in QQuickNativeMenuItem::createFromNonNativeItem.
+ if (nativeMenuItem->handle()) {
+ QQuickNativeMenuItem *before = nativeItems.value(index + 1);
+ handle->insertMenuItem(nativeMenuItem->handle(), before ? before->handle() : nullptr);
+ qCDebug(lcNativeMenus) << "inserted native menu item at index" << index
+ << "before" << (before ? before->debugText() : QStringLiteral("null"));
+
+ if (nativeMenuItem->subMenu() && QQuickMenuPrivate::get(nativeMenuItem->subMenu())->nativeItems.count()
+ < nativeMenuItem->subMenu()->count()) {
+ // We're inserting a sub-menu item, and it hasn't had native items added yet,
+ // which probably means it's a menu that's been added back in after being removed
+ // with takeMenu(). Sub-menus added for the first time have their native items already
+ // constructed by virtue of contentData_append. Sub-menus that are removed always
+ // have their native items destroyed and removed too.
+ recursivelyCreateNativeMenuItems(nativeMenuItem->subMenu());
+ }
+ }
+
+ nativeMenuItem.release();
+
+ qCDebug(lcNativeMenus) << "nativeItems now contains the following items:"
+ << nativeMenuItemListToString(nativeItems);
}
void QQuickMenuPrivate::moveItem(int from, int to)
{
contentModel->move(from, to);
+
+ if (maybeNativeHandle())
+ nativeItems.move(from, to);
}
-void QQuickMenuPrivate::removeItem(int index, QQuickItem *item)
+/*!
+ \internal
+
+ Removes the specified \a item, potentially destroying it depending on
+ \a destructionPolicy.
+
+ \note the native menu item is destroyed regardless of the destruction
+ policy, because it's an implementation detail and hence is not created by
+ or available to the user.
+*/
+void QQuickMenuPrivate::removeItem(int index, QQuickItem *item, DestructionPolicy destructionPolicy)
{
+ qCDebug(lcMenu) << "removeItem called with index" << index << "item" << item;
+
+ if (maybeNativeHandle())
+ removeNativeItem(index);
+
contentData.removeOne(item);
QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent);
@@ -278,9 +739,79 @@ void QQuickMenuPrivate::removeItem(int index, QQuickItem *item)
if (QQuickMenu *subMenu = menuItem->subMenu())
QQuickMenuPrivate::get(subMenu)->setParentMenu(nullptr);
QObjectPrivate::disconnect(menuItem, &QQuickMenuItem::triggered, this, &QQuickMenuPrivate::onItemTriggered);
+ QObjectPrivate::disconnect(menuItem, &QQuickMenuItem::implicitTextPaddingChanged, this, &QQuickMenuPrivate::updateTextPadding);
+ QObjectPrivate::disconnect(menuItem, &QQuickMenuItem::visibleChanged, this, &QQuickMenuPrivate::updateTextPadding);
QObjectPrivate::disconnect(menuItem, &QQuickItem::activeFocusChanged, this, &QQuickMenuPrivate::onItemActiveFocusChanged);
QObjectPrivate::disconnect(menuItem, &QQuickControl::hoveredChanged, this, &QQuickMenuPrivate::onItemHovered);
}
+
+ if (destructionPolicy == DestructionPolicy::Destroy)
+ item->deleteLater();
+
+ if (lcMenu().isDebugEnabled())
+ printContentModelItems();
+}
+
+void QQuickMenuPrivate::removeNativeItem(int index)
+{
+ // Either we're still using native menus and are removing item(s), or we've switched
+ // to a non-native menu; either way, we should actually have items to remove before we're called.
+ Q_ASSERT(handle);
+ Q_ASSERT_X(index >= 0 && index < nativeItems.size(), Q_FUNC_INFO, qPrintable(QString::fromLatin1(
+ "index %1 is less than 0 or greater than or equal to %2").arg(index).arg(nativeItems.size())));
+
+ // We can delete the item synchronously because there aren't any external (e.g. QML)
+ // references to it.
+ std::unique_ptr<QQuickNativeMenuItem> nativeItem(nativeItems.takeAt(index));
+ qCDebug(lcNativeMenus) << "removing native item" << nativeItem->debugText() << "at index" << index
+ << "from" << q_func() << "...";
+ if (QQuickMenu *subMenu = nativeItem->subMenu())
+ recursivelyDestroyNativeSubMenus(subMenu);
+
+ if (nativeItem->handle()) {
+ handle->removeMenuItem(nativeItem->handle());
+ syncWithNativeMenu();
+ }
+
+ qCDebug(lcNativeMenus).nospace() << "... after removing item at index " << index
+ << ", nativeItems now contains the following items: " << nativeMenuItemListToString(nativeItems);
+}
+
+void QQuickMenuPrivate::resetNativeData()
+{
+ qCDebug(lcNativeMenus) << "resetNativeData called on" << q_func();
+ handle.reset();
+ triedToCreateNativeMenu = false;
+}
+
+void QQuickMenuPrivate::recursivelyCreateNativeMenuItems(QQuickMenu *menu)
+{
+ auto *menuPrivate = QQuickMenuPrivate::get(menu);
+ // If we're adding a sub-menu, we need to ensure its handle has been created
+ // before trying to create native items for it.
+ if (!menuPrivate->triedToCreateNativeMenu)
+ menuPrivate->createNativeMenu();
+
+ const int qtyItemsToCreate = menuPrivate->contentModel->count();
+ if (menuPrivate->nativeItems.count() == qtyItemsToCreate)
+ return;
+
+ qCDebug(lcNativeMenus) << "recursively creating" << qtyItemsToCreate << "menu item(s) for" << menu;
+ Q_ASSERT(menuPrivate->nativeItems.count() == 0);
+ for (int i = 0; i < qtyItemsToCreate; ++i) {
+ QQuickItem *item = menu->itemAt(i);
+ menuPrivate->maybeCreateAndInsertNativeItem(i, item);
+ auto *menuItem = qobject_cast<QQuickMenuItem *>(item);
+ if (menuItem && menuItem->subMenu())
+ recursivelyCreateNativeMenuItems(menuItem->subMenu());
+ }
+}
+
+void QQuickMenuPrivate::printContentModelItems() const
+{
+ qCDebug(lcMenu) << "contentModel now contains:";
+ for (int i = 0; i < contentModel->count(); ++i)
+ qCDebug(lcMenu) << "-" << itemAt(i);
}
QQuickItem *QQuickMenuPrivate::beginCreateItem()
@@ -415,18 +946,28 @@ QQuickPopupPositioner *QQuickMenuPrivate::getPositioner()
void QQuickMenuPositioner::reposition()
{
QQuickMenu *menu = static_cast<QQuickMenu *>(popup());
- QQuickMenuPrivate *p = QQuickMenuPrivate::get(menu);
- if (p->parentMenu) {
- if (p->cascade) {
- if (p->popupItem->isMirrored())
- menu->setPosition(QPointF(-menu->width() - p->parentMenu->leftPadding() + menu->overlap(), -menu->topPadding()));
- else if (p->parentItem)
- menu->setPosition(QPointF(p->parentItem->width() + p->parentMenu->rightPadding() - menu->overlap(), -menu->topPadding()));
+ QQuickMenuPrivate *menu_d = QQuickMenuPrivate::get(menu);
+
+ if (QQuickMenu *parentMenu = menu_d->parentMenu) {
+ if (menu_d->cascade) {
+ // Align the menu to the frame of the parent menuItem, minus overlap. The position
+ // should be in the coordinate system of the parentItem.
+ if (menu_d->popupItem->isMirrored()) {
+ const qreal distanceToFrame = parentMenu->leftPadding();
+ const qreal menuX = -menu->width() - distanceToFrame + menu->overlap();
+ menu->setPosition({menuX, -menu->topPadding()});
+ } else if (menu_d->parentItem) {
+ const qreal distanceToFrame = parentMenu->rightPadding();
+ const qreal menuX = menu_d->parentItem->width() + distanceToFrame - menu->overlap();
+ menu->setPosition({menuX, -menu->topPadding()});
+ }
} else {
- menu->setPosition(QPointF(p->parentMenu->x() + (p->parentMenu->width() - menu->width()) / 2,
- p->parentMenu->y() + (p->parentMenu->height() - menu->height()) / 2));
+ const qreal menuX = parentMenu->x() + (parentMenu->width() - menu->width()) / 2;
+ const qreal menuY = parentMenu->y() + (parentMenu->height() - menu->height()) / 2;
+ menu->setPosition({menuX, menuY});
}
}
+
QQuickPopupPositioner::reposition();
}
@@ -474,6 +1015,36 @@ bool QQuickMenuPrivate::blockInput(QQuickItem *item, const QPointF &point) const
return (cascade && parentMenu && contains(point)) || QQuickPopupPrivate::blockInput(item, point);
}
+/*! \internal
+ QQuickPopupWindow::event() calls this to handle the release event of a
+ menu drag-press-release gesture, because the \a eventPoint does not have
+ a grabber within the popup window. This override finds and activates the
+ appropriate menu item, as if it had been pressed and released.
+ Returns true on success, to indicate that handling \a eventPoint is done.
+ */
+bool QQuickMenuPrivate::handleReleaseWithoutGrab(const QEventPoint &eventPoint)
+{
+ if (!contains(eventPoint.scenePosition()))
+ return false;
+
+ QQuickMenuItem *menuItem = nullptr;
+ // Usually, hover events have occurred, and currentIndex is set.
+ // If not, use eventPoint.position() for picking.
+ if (currentIndex < 0) {
+ auto *list = qobject_cast<QQuickListView *>(contentItem);
+ if (!list)
+ return false;
+ menuItem = qobject_cast<QQuickMenuItem *>(list->itemAt(eventPoint.position().x(), eventPoint.position().y()));
+ } else {
+ menuItem = qobject_cast<QQuickMenuItem *>(itemAt(currentIndex));
+ }
+ if (Q_LIKELY(menuItem)) {
+ menuItem->animateClick();
+ return true;
+ }
+ return false;
+}
+
void QQuickMenuPrivate::onItemHovered()
{
Q_Q(QQuickMenu);
@@ -528,6 +1099,30 @@ void QQuickMenuPrivate::onItemActiveFocusChanged()
setCurrentIndex(indexOfItem, control ? control->focusReason() : Qt::OtherFocusReason);
}
+void QQuickMenuPrivate::updateTextPadding()
+{
+ Q_Q(QQuickMenu);
+ if (!complete)
+ return;
+
+ qreal padding = 0;
+ for (int i = 0; i < q->count(); ++i) {
+ if (const auto menuItem = qobject_cast<QQuickMenuItem *>(itemAt(i)))
+ if (menuItem->isVisible())
+ padding = qMax(padding, menuItem->implicitTextPadding());
+ }
+
+ if (padding == textPadding)
+ return;
+
+ textPadding = padding;
+
+ for (int i = 0; i < q->count(); ++i) {
+ if (const auto menuItem = qobject_cast<QQuickMenuItem *>(itemAt(i)))
+ emit menuItem->textPaddingChanged();
+ }
+}
+
QQuickMenu *QQuickMenuPrivate::currentSubMenu() const
{
if (!currentItem)
@@ -741,11 +1336,17 @@ QQuickMenu::QQuickMenu(QObject *parent)
QQuickMenu::~QQuickMenu()
{
Q_D(QQuickMenu);
- // We have to do this to ensure that the change listeners are removed.
- // It's too late to do this in ~QQuickMenuPrivate, as contentModel has already
- // been destroyed before that is called.
+ qCDebug(lcNativeMenus) << "destroying" << this
+ << "item count:"
+ << d->contentModel->count()
+ << "native item count:" << d->nativeItems.count();
+ // We have to remove items to ensure that our change listeners on the item
+ // are removed. It's too late to do this in ~QQuickMenuPrivate, as
+ // contentModel has already been destroyed before that is called.
+ // Destruction isn't necessary for the QQuickItems themselves, but it is
+ // required for the native menus (see comment in removeItem()).
while (d->contentModel->count() > 0)
- d->removeItem(0, d->itemAt(0));
+ d->removeItem(0, d->itemAt(0), QQuickMenuPrivate::DestructionPolicy::Destroy);
if (d->contentItem) {
QQuickItemPrivate::get(d->contentItem)->removeItemChangeListener(d, QQuickItemPrivate::Children);
@@ -797,8 +1398,9 @@ void QQuickMenu::insertItem(int index, QQuickItem *item)
if (oldIndex != -1) {
if (oldIndex < index)
--index;
- if (oldIndex != index)
+ if (oldIndex != index) {
d->moveItem(oldIndex, index);
+ }
} else {
d->insertItem(index, item);
}
@@ -838,8 +1440,7 @@ void QQuickMenu::removeItem(QQuickItem *item)
if (index == -1)
return;
- d->removeItem(index, item);
- item->deleteLater();
+ d->removeItem(index, item, QQuickMenuPrivate::DestructionPolicy::Destroy);
}
/*!
@@ -953,6 +1554,7 @@ QQuickMenu *QQuickMenu::takeMenu(int index)
d->removeItem(index, item);
item->deleteLater();
+
return subMenu;
}
@@ -966,11 +1568,18 @@ QQuickMenu *QQuickMenu::takeMenu(int index)
QQuickAction *QQuickMenu::actionAt(int index) const
{
Q_D(const QQuickMenu);
- QQuickAbstractButton *item = qobject_cast<QQuickAbstractButton *>(d->itemAt(index));
- if (!item)
- return nullptr;
+ if (!const_cast<QQuickMenuPrivate *>(d)->maybeNativeHandle()) {
+ QQuickAbstractButton *item = qobject_cast<QQuickAbstractButton *>(d->itemAt(index));
+ if (!item)
+ return nullptr;
- return item->action();
+ return item->action();
+ } else {
+ if (index < 0 || index >= d->nativeItems.size())
+ return nullptr;
+
+ return d->nativeItems.at(index)->action();
+ }
}
/*!
@@ -1049,6 +1658,43 @@ QQuickAction *QQuickMenu::takeAction(int index)
return action;
}
+bool QQuickMenu::isVisible() const
+{
+ Q_D(const QQuickMenu);
+ if (d->maybeNativeHandle())
+ return d->visible;
+ return QQuickPopup::isVisible();
+}
+
+void QQuickMenu::setVisible(bool visible)
+{
+ Q_D(QQuickMenu);
+ if (visible == d->visible)
+ return;
+ if (visible && !parentItem()) {
+ qmlWarning(this) << "cannot show menu: parent is null";
+ return;
+ }
+
+ if (visible && ((d->useNativeMenu() && !d->maybeNativeHandle())
+ || (!d->useNativeMenu() && d->maybeNativeHandle()))) {
+ // We've been made visible, and our actual native state doesn't match our requested state,
+ // which means AA_DontUseNativeMenuWindows was set while we were visible or had a parent.
+ // Try to sync our state again now that we're about to be re-opened.
+ qCDebug(lcNativeMenus) << "setVisible called - useNativeMenu:" << d->useNativeMenu()
+ << "maybeNativeHandle:" << d->maybeNativeHandle();
+ d->syncWithUseNativeMenu();
+ }
+ if (d->maybeNativeHandle()) {
+ d->setNativeMenuVisible(visible);
+ return;
+ }
+
+ // Either the native menu wasn't wanted, or it couldn't be created;
+ // show the non-native menu.
+ QQuickPopup::setVisible(visible);
+}
+
/*!
\qmlproperty model QtQuick.Controls::Menu::contentModel
\readonly
@@ -1124,6 +1770,8 @@ void QQuickMenu::setTitle(const QString &title)
if (title == d->title)
return;
d->title = title;
+ if (d->handle)
+ d->handle->setText(title);
emit titleChanged(title);
}
@@ -1139,6 +1787,8 @@ void QQuickMenu::setTitle(const QString &title)
\include qquickicon.qdocinc grouped-properties
+ \include qquickmenu.qdocinc non-native-only-property
+
\sa AbstractButton::text, AbstractButton::display, {Icons in Qt Quick Controls}
*/
@@ -1170,6 +1820,8 @@ void QQuickMenu::setIcon(const QQuickIcon &icon)
\note Changing the value of the property has no effect while the menu is open.
+ \include qquickmenu.qdocinc non-native-only-property
+
\sa overlap
*/
bool QQuickMenu::cascade() const
@@ -1210,6 +1862,8 @@ void QQuickMenu::resetCascade()
\note Changing the value of the property has no effect while the menu is open.
+ \include qquickmenu.qdocinc non-native-only-property
+
\sa cascade
*/
qreal QQuickMenu::overlap() const
@@ -1242,6 +1896,9 @@ void QQuickMenu::setOverlap(qreal overlap)
}
\endcode
+ \note delegates will only be visible when using a \l {Native Menus}
+ {non-native Menu}.
+
\sa Action
*/
QQmlComponent *QQuickMenu::delegate() const
@@ -1268,6 +1925,8 @@ void QQuickMenu::setDelegate(QQmlComponent *delegate)
Menu items can be highlighted by mouse hover or keyboard navigation.
+ \include qquickmenu.qdocinc non-native-only-property
+
\sa MenuItem::highlighted
*/
int QQuickMenu::currentIndex() const
@@ -1325,6 +1984,9 @@ void QQuickMenu::popup(const QPointF &pos, QQuickItem *menuItem)
if (menuItem)
d->setCurrentIndex(d->contentModel->indexOf(menuItem, nullptr), Qt::PopupFocusReason);
+ else
+ d->setCurrentIndex(-1, Qt::PopupFocusReason);
+
open();
}
@@ -1336,7 +1998,9 @@ void QQuickMenu::popup(const QPointF &pos, QQuickItem *menuItem)
Opens the menu at the mouse cursor on desktop platforms that have a mouse cursor
available, and otherwise centers the menu over its \a parent item.
- The menu can be optionally aligned to a specific menu \a item.
+ The menu can be optionally aligned to a specific menu \a item. This item will
+ then become \l {currentIndex}{current.} If no \a item is specified, \l currentIndex
+ will be set to \c -1.
\sa Popup::open()
*/
@@ -1349,7 +2013,9 @@ void QQuickMenu::popup(const QPointF &pos, QQuickItem *menuItem)
Opens the menu at the specified position \a pos in the popups coordinate system,
that is, a coordinate relative to its \a parent item.
- The menu can be optionally aligned to a specific menu \a item.
+ The menu can be optionally aligned to a specific menu \a item. This item will
+ then become \l {currentIndex}{current.} If no \a item is specified, \l currentIndex
+ will be set to \c -1.
\sa Popup::open()
*/
@@ -1362,7 +2028,9 @@ void QQuickMenu::popup(const QPointF &pos, QQuickItem *menuItem)
Opens the menu at the specified position \a x, \a y in the popups coordinate system,
that is, a coordinate relative to its \a parent item.
- The menu can be optionally aligned to a specific menu \a item.
+ The menu can be optionally aligned to a specific menu \a item. This item will
+ then become \l {currentIndex}{current.} If no \a item is specified, \l currentIndex
+ will be set to \c -1.
\sa dismiss(), Popup::open()
*/
@@ -1434,9 +2102,10 @@ void QQuickMenu::popup(QQmlV4FunctionPtr args)
Closes all menus in the hierarchy that this menu belongs to.
- \note Unlike \l {Popup::}{close()} that only closes a menu and its sub-menus,
- \c dismiss() closes the whole hierarchy of menus, including the parent menus.
- In practice, \c close() is suitable e.g. for implementing navigation in a
+ \note Unlike \l {Popup::}{close()} that only closes a menu and its
+ sub-menus (when using \l {Native Menus}{non-native menus}), \c dismiss()
+ closes the whole hierarchy of menus, including the parent menus. In
+ practice, \c close() is suitable e.g. for implementing navigation in a
hierarchy of menus, and \c dismiss() is the appropriate method for closing
the whole hierarchy of menus.
@@ -1456,6 +2125,8 @@ void QQuickMenu::componentComplete()
Q_D(QQuickMenu);
QQuickPopup::componentComplete();
d->resizeItems();
+ d->updateTextPadding();
+ d->syncWithUseNativeMenu();
}
void QQuickMenu::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
@@ -1480,12 +2151,16 @@ void QQuickMenu::itemChange(QQuickItem::ItemChange change, const QQuickItem::Ite
Q_D(QQuickMenu);
QQuickPopup::itemChange(change, data);
- if (change == QQuickItem::ItemVisibleHasChanged) {
+ switch (change) {
+ case QQuickItem::ItemVisibleHasChanged:
if (!data.boolValue && d->cascade) {
// Ensure that when the menu isn't visible, there's no current item
// the next time it's opened.
d->setCurrentIndex(-1, Qt::OtherFocusReason);
}
+ break;
+ default:
+ break;
}
}
diff --git a/src/quicktemplates/qquickmenu_p.h b/src/quicktemplates/qquickmenu_p.h
index 0ff8a121ac..ed08537fdb 100644
--- a/src/quicktemplates/qquickmenu_p.h
+++ b/src/quicktemplates/qquickmenu_p.h
@@ -97,6 +97,9 @@ public:
Q_REVISION(2, 3) Q_INVOKABLE void removeAction(QQuickAction *action);
Q_REVISION(2, 3) Q_INVOKABLE QQuickAction *takeAction(int index);
+ bool isVisible() const override;
+ void setVisible(bool visible) override;
+
void popup(QQuickItem *menuItem = nullptr);
void popup(const QPointF &pos, QQuickItem *menuItem = nullptr);
diff --git a/src/quicktemplates/qquickmenu_p_p.h b/src/quicktemplates/qquickmenu_p_p.h
index 552f35794a..be607c37c9 100644
--- a/src/quicktemplates/qquickmenu_p_p.h
+++ b/src/quicktemplates/qquickmenu_p_p.h
@@ -18,6 +18,8 @@
#include <QtCore/qlist.h>
#include <QtCore/qpointer.h>
+#include <QtGui/qpa/qplatformmenu.h>
+
#include <QtQuickTemplates2/private/qquickmenu_p.h>
#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
@@ -27,6 +29,8 @@ class QQuickAction;
class QQmlComponent;
class QQmlObjectModel;
class QQuickMenuItem;
+class QQuickNativeMenuItem;
+class QQuickMenuBar;
class Q_QUICKTEMPLATES2_EXPORT QQuickMenuPrivate : public QQuickPopupPrivate
{
@@ -42,10 +46,33 @@ public:
void init();
+ QPlatformMenu *nativeHandle();
+ QPlatformMenu *maybeNativeHandle() const;
+ QQuickMenu *rootMenu() const;
+ bool useNativeMenu() const;
+ bool createNativeMenu();
+ void removeNativeMenu();
+ void syncWithNativeMenu();
+ void syncWithUseNativeMenu();
+ static void recursivelyDestroyNativeSubMenus(QQuickMenu *menu);
+ void setNativeMenuVisible(bool visible);
+
QQuickItem *itemAt(int index) const;
void insertItem(int index, QQuickItem *item);
+ void maybeCreateAndInsertNativeItem(int index, QQuickItem *item);
void moveItem(int from, int to);
- void removeItem(int index, QQuickItem *item);
+ enum class DestructionPolicy {
+ Destroy,
+ DoNotDestroy
+ };
+ void removeItem(int index, QQuickItem *item,
+ DestructionPolicy destructionPolicy = DestructionPolicy::DoNotDestroy);
+ void removeNativeItem(int index);
+ void resetNativeData();
+
+ static void recursivelyCreateNativeMenuItems(QQuickMenu *menu);
+
+ void printContentModelItems() const;
QQuickItem *beginCreateItem();
void completeCreateItem();
@@ -66,10 +93,12 @@ public:
bool prepareEnterTransition() override;
bool prepareExitTransition() override;
bool blockInput(QQuickItem *item, const QPointF &point) const override;
+ bool handleReleaseWithoutGrab(const QEventPoint &eventPoint) override;
void onItemHovered();
void onItemTriggered();
void onItemActiveFocusChanged();
+ void updateTextPadding();
QQuickMenu *currentSubMenu() const;
void setParentMenu(QQuickMenu *parent);
@@ -92,11 +121,14 @@ public:
static void contentData_clear(QQmlListProperty<QObject> *prop);
QPalette defaultPalette() const override;
+ virtual QQuickPopup::PopupType resolvedPopupType() const override;
bool cascade = false;
+ bool triedToCreateNativeMenu = false;
int hoverTimer = 0;
int currentIndex = -1;
qreal overlap = 0;
+ qreal textPadding = 0;
QPointer<QQuickMenu> parentMenu;
QPointer<QQuickMenuItem> currentItem;
QQuickItem *contentItem = nullptr; // TODO: cleanup
@@ -105,6 +137,12 @@ public:
QQmlComponent *delegate = nullptr;
QString title;
QQuickIcon icon;
+
+ // For native menu support.
+ std::unique_ptr<QPlatformMenu> handle = nullptr;
+ QList<QQuickNativeMenuItem *> nativeItems;
+ QPointer<QQuickMenuBar> menuBar;
+ qreal lastDevicePixelRatio = 0;
};
QT_END_NAMESPACE
diff --git a/src/quicktemplates/qquickmenubar.cpp b/src/quicktemplates/qquickmenubar.cpp
index 62c7680d0d..76f06adc16 100644
--- a/src/quicktemplates/qquickmenubar.cpp
+++ b/src/quicktemplates/qquickmenubar.cpp
@@ -42,16 +42,29 @@ QT_BEGIN_NAMESPACE
\l {removeMenu}{remove}, and \l {takeMenu}{take} menus dynamically. The
menus in a menu bar can be accessed using \l menuAt().
+ \section1 Native menu bars
+
+ Since Qt 6.8, a MenuBar is implemented as a native menu bar on \macos. As a
+ result, all Menus, MenuItems and MenuBarItems within a MenuBar will also be native.
+ While this has the advantage that everything will look native, it also comes with the
+ disadvantage that the delegates set on the mentioned controls will not be used
+ for rendering.
+ If a native MenuBar is not wanted, you can set
+ \l {Qt::AA_DontUseNativeMenuBar}{QGuiApplication::setAttribute(Qt::AA_DontUseNativeMenuBar)}
+ to disable it.
+
\sa {Customizing MenuBar}, Menu, MenuBarItem, {Menu Controls},
{Focus Management in Qt Quick Controls}
*/
-QQuickItem *QQuickMenuBarPrivate::beginCreateItem(QQuickMenu *menu)
+Q_STATIC_LOGGING_CATEGORY(lcMenuBar, "qt.quick.controls.menubar")
+
+static const char* kCreatedFromDelegate = "_qt_createdFromDelegate";
+
+QQuickItem *QQuickMenuBarPrivate::createItemFromDelegate()
{
Q_Q(QQuickMenuBar);
- if (!delegate)
- return nullptr;
-
+ Q_ASSERT(delegate);
QQmlContext *context = delegate->creationContext();
if (!context)
context = qmlContext(q);
@@ -63,45 +76,94 @@ QQuickItem *QQuickMenuBarPrivate::beginCreateItem(QQuickMenu *menu)
return nullptr;
}
- if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item))
- menuBarItem->setMenu(menu);
- item->setParentItem(q);
QQml_setParent_noEvent(item, q);
+ delegate->completeCreate();
return item;
}
-void QQuickMenuBarPrivate::completeCreateItem()
+QQuickMenuBarItem *QQuickMenuBarPrivate::createMenuBarItem(QQuickMenu *menu)
{
- if (!delegate)
- return;
+ Q_Q(QQuickMenuBar);
- delegate->completeCreate();
+ QQuickMenuBarItem *menuBarItem = nullptr;
+ if (delegate) {
+ QQuickItem *item = createItemFromDelegate();
+ menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
+ if (!menuBarItem) {
+ qmlWarning(q) << "cannot insert menu: the delegate is not a MenuBarItem.";
+ delete item;
+ }
+ }
+
+ if (!menuBarItem) {
+ // When we fail to create a delegate item, create a hidden placeholder
+ // instead. This is needed, since we store the menus inside the container
+ // using MenuBarItem. And without a MenuBarItem, we would therefore lose
+ // the menu, even if the delegate is changed later.
+ qCDebug(lcMenuBar) << "creating hidden placeholder MenuBarItem for:" << menu->title();
+ menuBarItem = new QQuickMenuBarItem(q);
+ menuBarItem->setParentItem(q);
+ menuBarItem->setVisible(false);
+ }
+
+ menuBarItem->setMenu(menu);
+
+ // Tag the menuBarItem, so that we know which container items to change if the
+ // delegate is changed. This is needed since you can add MenuBarItems directly
+ // to the menu bar, which should not change when the delegate changes.
+ menuBarItem->setProperty(kCreatedFromDelegate, true);
+
+ return menuBarItem;
}
-QQuickItem *QQuickMenuBarPrivate::createItem(QQuickMenu *menu)
+void QQuickMenuBarPrivate::openCurrentMenu()
{
- QQuickItem *item = beginCreateItem(menu);
- completeCreateItem();
- return item;
+ if (!currentItem || currentMenuOpen)
+ return;
+ QQuickMenu *menu = currentItem->menu();
+ if (!menu || menu->isOpened())
+ return;
+
+#ifdef Q_OS_MACOS
+ // On macOS, the menu should open underneath the MenuBar
+ Q_Q(QQuickMenuBar);
+ const QPointF posInParentItem = q->mapToItem(currentItem, {currentItem->x(), q->height()});
+#else
+ // On other platforms, it should open underneath the MenuBarItem
+ const QPointF posInParentItem{0, currentItem->y() + currentItem->height()};
+#endif
+
+ // Store explicit if the current menu is logically supposed to be open.
+ // menu->isVisible() is async when using top-level menus, and will not become
+ // "true" before the menu is actually shown by the OS. This will cause us to
+ // lose track of if a menu is (supposed to be) open, if relying on menu->isVisible().
+ currentMenuOpen = true;
+
+ // The position should be the coordinate system of the parent item. Note that
+ // the parentItem() of a menu will be the MenuBarItem (currentItem), and not the
+ // MenuBar (even if parent() usually points to the MenuBar).
+ menu->popup(posInParentItem);
}
-void QQuickMenuBarPrivate::toggleCurrentMenu(bool visible, bool activate)
+void QQuickMenuBarPrivate::closeCurrentMenu()
{
- if (!currentItem || visible == popupMode)
+ if (!currentItem || !currentMenuOpen)
return;
-
+ currentMenuOpen = false;
QQuickMenu *menu = currentItem->menu();
+ QScopedValueRollback triggerRollback(closingCurrentMenu, true);
+ menu->dismiss();
+}
- triggering = true;
- popupMode = visible;
- if (menu)
- menu->setVisible(visible);
- if (!visible)
- currentItem->forceActiveFocus();
- else if (menu && activate)
- menu->setCurrentIndex(0);
- triggering = false;
+void QQuickMenuBarPrivate::activateMenuItem(int index)
+{
+ if (!currentItem)
+ return;
+ QQuickMenu *menu = currentItem->menu();
+ if (!menu)
+ return;
+ menu->setCurrentIndex(index);
}
void QQuickMenuBarPrivate::activateItem(QQuickMenuBarItem *item)
@@ -109,23 +171,20 @@ void QQuickMenuBarPrivate::activateItem(QQuickMenuBarItem *item)
if (currentItem == item)
return;
+ const bool stayOpen = currentMenuOpen;
+
if (currentItem) {
currentItem->setHighlighted(false);
- if (popupMode) {
- if (QQuickMenu *menu = currentItem->menu())
- menu->dismiss();
- }
- }
-
- if (item) {
- item->setHighlighted(true);
- if (popupMode) {
- if (QQuickMenu *menu = item->menu())
- menu->open();
- }
+ closeCurrentMenu();
}
currentItem = item;
+
+ if (currentItem) {
+ currentItem->setHighlighted(true);
+ if (stayOpen)
+ openCurrentMenu();
+ }
}
void QQuickMenuBarPrivate::activateNextItem()
@@ -162,19 +221,34 @@ void QQuickMenuBarPrivate::onItemTriggered()
return;
if (item == currentItem) {
- toggleCurrentMenu(!popupMode, false);
+ if (currentMenuOpen) {
+ closeCurrentMenu();
+ currentItem->forceActiveFocus();
+ } else {
+ openCurrentMenu();
+ }
} else {
- popupMode = true;
activateItem(item);
+ openCurrentMenu();
}
}
-void QQuickMenuBarPrivate::onMenuAboutToHide()
+void QQuickMenuBarPrivate::onMenuAboutToHide(QQuickMenu *menu)
{
- if (triggering || !currentItem || !currentItem->isHighlighted())
+ if (closingCurrentMenu) {
+ // We only react on a menu closing if it's
+ // initiated from outside of QQuickMenuBar.
+ return;
+ }
+
+ if (!currentItem || currentItem->menu() != menu)
+ return;
+
+ currentMenuOpen = false;
+
+ if (!currentItem->isHighlighted() || currentItem->isHovered())
return;
- popupMode = false;
activateItem(nullptr);
}
@@ -220,14 +294,32 @@ void QQuickMenuBarPrivate::itemImplicitHeightChanged(QQuickItem *item)
void QQuickMenuBarPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
{
- QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
- if (QQuickMenu *menu = qobject_cast<QQuickMenu *>(obj))
- obj = QQuickMenuBarPrivate::get(menuBar)->createItem(menu);
+ auto menuBar = static_cast<QQuickMenuBar *>(prop->object);
+ auto menuBarPriv = QQuickMenuBarPrivate::get(menuBar);
+
+ if (auto *menu = qobject_cast<QQuickMenu *>(obj)) {
+ QQuickMenuBarItem *delegateItem = menuBarPriv->createMenuBarItem(menu);
+ menuBarPriv->insertMenu(menuBar->count(), menu, delegateItem);
+ QQuickContainerPrivate::contentData_append(prop, delegateItem);
+ return;
+ }
+
+ if (auto *menuBarItem = qobject_cast<QQuickMenuBarItem *>(obj)) {
+ menuBarPriv->insertMenu(menuBar->count(), menuBarItem->menu(), menuBarItem);
+ QQuickContainerPrivate::contentData_append(prop, menuBarItem);
+ return;
+ }
+
QQuickContainerPrivate::contentData_append(prop, obj);
}
void QQuickMenuBarPrivate::menus_append(QQmlListProperty<QQuickMenu> *prop, QQuickMenu *obj)
{
+ // This function is only called if the application assigns a list of menus
+ // directly to the 'menus' property. Otherwise, contentData_append is used.
+ // Since the functions belonging to the 'menus' list anyway returns data from
+ // the menuBar, calls such as "menuBar.menus.length" works as expected
+ // regardless of how the menus were added.
QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
menuBar->addMenu(obj);
}
@@ -255,6 +347,283 @@ QPalette QQuickMenuBarPrivate::defaultPalette() const
return QQuickTheme::palette(QQuickTheme::MenuBar);
}
+QWindow* QQuickMenuBarPrivate::window() const
+{
+ Q_Q(const QQuickMenuBar);
+ QObject *obj = q->parent();
+ while (obj) {
+ if (QWindow *window = qobject_cast<QWindow *>(obj))
+ return window;
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (item && item->window())
+ return item->window();
+ obj = obj->parent();
+ }
+ return nullptr;
+}
+
+int QQuickMenuBarPrivate::menuIndex(QQuickMenu *menu) const
+{
+ Q_Q(const QQuickMenuBar);
+ for (int i = 0; i < q->count(); ++i) {
+ if (q->menuAt(i) == menu)
+ return i;
+ }
+
+ return -1;
+}
+
+QPlatformMenuBar* QQuickMenuBarPrivate::nativeHandle() const
+{
+ return handle.get();
+}
+
+void QQuickMenuBarPrivate::insertNativeMenu(QQuickMenu *menu)
+{
+ Q_Q(QQuickMenuBar);
+ Q_ASSERT(handle);
+ Q_ASSERT(menu);
+
+ QPlatformMenu *insertBeforeHandle = nullptr;
+
+ // This function assumes that the QQuickMenuBarItem that corresponds to \a menu
+ // has already been added to the container at the correct index. So we search for
+ // it, to determine where to insert it in the native menubar. Since the QPA API
+ // expects a pointer to the QPlatformMenu that comes after it, we need to search
+ // for that one as well, since some MenuBarItems in the container can be hidden.
+ bool foundInContainer = false;
+ for (int i = 0; i < q->count(); ++i) {
+ if (q->menuAt(i) != menu)
+ continue;
+ foundInContainer = true;
+
+ for (int j = i + 1; j < q->count(); ++j) {
+ insertBeforeHandle = QQuickMenuPrivate::get(q->menuAt(j))->maybeNativeHandle();
+ if (insertBeforeHandle)
+ break;
+ }
+
+ break;
+ }
+
+ Q_ASSERT(foundInContainer);
+ QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu);
+ if (QPlatformMenu *menuHandle = menuPrivate->nativeHandle()) {
+ qCDebug(lcMenuBar) << "insert native menu:" << menu->title() << menuHandle << "before:" << insertBeforeHandle;
+ handle->insertMenu(menuPrivate->nativeHandle(), insertBeforeHandle);
+ } else {
+ qmlWarning(q) << "failed to create native menu for:" << menu->title();
+ }
+}
+
+void QQuickMenuBarPrivate::removeNativeMenu(QQuickMenu *menu)
+{
+ Q_ASSERT(handle);
+ Q_ASSERT(menu);
+
+ QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu);
+ if (!menuPrivate->maybeNativeHandle())
+ return;
+
+ qCDebug(lcMenuBar) << "remove native menu:" << menu << menu->title();
+ handle->removeMenu(menuPrivate->nativeHandle());
+ menuPrivate->removeNativeMenu();
+}
+
+void QQuickMenuBarPrivate::syncMenuBarItemVisibilty(QQuickMenuBarItem *menuBarItem)
+{
+ if (!handle) {
+ // We only need to update visibility on native menu bar items
+ return;
+ }
+
+ QQuickMenu *menu = menuBarItem->menu();
+ if (!menu)
+ return;
+ QQuickMenuPrivate *menuPrivate = QQuickMenuPrivate::get(menu);
+
+ if (menuBarItem->isVisible()) {
+ Q_ASSERT(!menuPrivate->maybeNativeHandle());
+ insertNativeMenu(menu);
+ } else {
+ if (menuPrivate->maybeNativeHandle())
+ removeNativeMenu(menu);
+ }
+}
+
+void QQuickMenuBarPrivate::insertMenu(int index, QQuickMenu *menu, QQuickMenuBarItem *menuBarItem)
+{
+ Q_Q(QQuickMenuBar);
+ if (!menu) {
+ qmlWarning(q) << "cannot insert menu: menu is null.";
+ return;
+ }
+
+ auto menuPrivate = QQuickMenuPrivate::get(menu);
+ menuPrivate->menuBar = q;
+
+ QObject::connect(menuBarItem, &QQuickMenuBarItem::visibleChanged, [this, menuBarItem]{
+ syncMenuBarItemVisibilty(menuBarItem);
+ });
+
+ // Always insert menu into the container, even when using a native
+ // menubar, so that container API such as 'count' and 'itemAt'
+ // continues to work as expected.
+ q->insertItem(index, menuBarItem);
+
+ // Create or remove a native (QPlatformMenu) menu. Note that we should only create
+ // a native menu if it's supposed to be visible in the menu bar.
+ if (menuBarItem->isVisible()) {
+ if (handle)
+ insertNativeMenu(menu);
+ } else {
+ if (menuPrivate->maybeNativeHandle()) {
+ // If the menu was added from an explicit call to addMenu(m), it will have been
+ // created before we enter here. And in that case, QQuickMenuBar::useNativeMenu(m)
+ // was never called, and a QPlatformMenu might have been created for it. In that
+ // case, we remove it again now, since the menu is not supposed to be visible in
+ // the menu bar.
+ menuPrivate->removeNativeMenu();
+ }
+ }
+}
+
+QQuickMenu *QQuickMenuBarPrivate::takeMenu(int index)
+{
+ Q_Q(QQuickMenuBar);
+ QQuickItem *item = q->itemAt(index);
+ Q_ASSERT(item);
+ QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
+ if (!menuBarItem) {
+ qmlWarning(q) << "cannot take/remove menu: item at index " << index << " is not a MenuBarItem.";
+ return nullptr;
+ }
+ QQuickMenu *menu = menuBarItem->menu();
+ if (!menu) {
+ qmlWarning(q) << "cannot take/remove menu: MenuBarItem.menu at index " << index << " is null.";
+ return nullptr;
+ }
+
+ // Dismiss the menu if it's open. Otherwise, when we now remove it from
+ // the menubar, it will stay open without the user being able to dismiss
+ // it (at least if it's non-native).
+ menu->dismiss();
+
+ if (item == currentItem)
+ activateItem(nullptr);
+
+ if (QQuickMenuPrivate::get(menu)->maybeNativeHandle())
+ removeNativeMenu(menu);
+
+ removeItem(index, item);
+
+ // Delete the MenuBarItem. This will also cause the menu to be deleted by
+ // the garbage collector, unless other QML references are being held to it.
+ // Note: We might consider leaving it to the garbage collector to also
+ // delete the MenuBarItem in the future.
+ item->deleteLater();
+
+ QQuickMenuPrivate::get(menu)->menuBar = nullptr;
+ menuBarItem->disconnect(q);
+
+ return menu;
+}
+
+bool QQuickMenuBarPrivate::useNativeMenuBar() const
+{
+ // We current only use native menu bars on macOS. Especially, the
+ // QPA menu bar for Windows is old and unused, and looks broken and non-native.
+#ifdef Q_OS_MACOS
+ return !QCoreApplication::testAttribute(Qt::AA_DontUseNativeMenuBar);
+#else
+ return false;
+#endif
+}
+
+bool QQuickMenuBarPrivate::useNativeMenu(const QQuickMenu *menu) const
+{
+ Q_Q(const QQuickMenuBar);
+ if (!useNativeMenuBar())
+ return false;
+
+ // Since we cannot hide a QPlatformMenu, we have to avoid
+ // creating it if it shouldn't be visible in the menu bar.
+ for (int i = 0; i < q->count(); ++i) {
+ if (q->menuAt(i) == menu)
+ return itemAt(i)->isVisible();
+ }
+
+ return true;
+}
+
+void QQuickMenuBarPrivate::syncNativeMenuBarVisible()
+{
+ Q_Q(QQuickMenuBar);
+ if (!componentComplete)
+ return;
+
+ const bool shouldBeVisible = q->isVisible() && useNativeMenuBar();
+ qCDebug(lcMenuBar) << "syncNativeMenuBarVisible called - q->isVisible()" << q->isVisible()
+ << "useNativeMenuBar()" << useNativeMenuBar() << "handle" << handle.get();
+ if (shouldBeVisible && !handle)
+ createNativeMenuBar();
+ else if (!shouldBeVisible && handle)
+ removeNativeMenuBar();
+}
+
+void QQuickMenuBarPrivate::createNativeMenuBar()
+{
+ Q_Q(QQuickMenuBar);
+ Q_ASSERT(!handle);
+ qCDebug(lcMenuBar) << "creating native menubar";
+
+ handle.reset(QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar());
+ if (!handle) {
+ qCDebug(lcMenuBar) << "QPlatformTheme failed to create a QPlatformMenuBar!";
+ return;
+ }
+
+ handle->handleReparent(window());
+ qCDebug(lcMenuBar) << "native menubar parented to window:" << handle->parentWindow();
+
+ // Add all the native menus. We need to do this right-to-left
+ // because of the QPA API (insertBefore).
+ for (int i = q->count() - 1; i >= 0; --i) {
+ if (QQuickMenu *menu = q->menuAt(i)) {
+ if (useNativeMenu(menu))
+ insertNativeMenu(menu);
+ }
+ }
+
+ // Hide the non-native menubar and set it's height to 0. The
+ // latter will cause a relayout to happen in ApplicationWindow
+ // which effectively removes the menubar from the contentItem.
+ setCulled(true);
+ q->setHeight(0);
+}
+
+void QQuickMenuBarPrivate::removeNativeMenuBar()
+{
+ Q_Q(QQuickMenuBar);
+ Q_ASSERT(handle);
+ qCDebug(lcMenuBar) << "removing native menubar";
+
+ // Remove all native menus.
+ for (int i = 0; i < q->count(); ++i) {
+ if (QQuickMenu *menu = q->menuAt(i))
+ removeNativeMenu(menu);
+ }
+
+ // Delete the menubar
+ handle.reset();
+
+ // Show the non-native menubar and reset it's height. The
+ // latter will cause a relayout to happen in ApplicationWindow
+ // which will effectively add the menubar to the contentItem.
+ setCulled(false);
+ q->resetHeight();
+}
+
QQuickMenuBar::QQuickMenuBar(QQuickItem *parent)
: QQuickContainer(*(new QQuickMenuBarPrivate), parent)
{
@@ -264,6 +633,13 @@ QQuickMenuBar::QQuickMenuBar(QQuickItem *parent)
setFocusPolicy(Qt::ClickFocus);
}
+QQuickMenuBar::~QQuickMenuBar()
+{
+ Q_D(QQuickMenuBar);
+ if (d->handle)
+ d->removeNativeMenuBar();
+}
+
/*!
\qmlproperty Component QtQuick.Controls::MenuBar::delegate
@@ -285,6 +661,21 @@ void QQuickMenuBar::setDelegate(QQmlComponent *delegate)
return;
d->delegate = delegate;
+
+ for (int i = count() - 1; i >= 0; --i) {
+ auto item = itemAt(i);
+ if (!item->property(kCreatedFromDelegate).toBool())
+ continue;
+
+ QQuickMenuBarItem *menuBarItem = static_cast<QQuickMenuBarItem *>(item);
+ if (QQuickMenu *menu = menuBarItem->menu()) {
+ removeMenu(menu);
+ d->insertMenu(i, menu, d->createMenuBarItem(menu));
+ } else {
+ removeItem(menuBarItem);
+ }
+ }
+
emit delegateChanged();
}
@@ -310,7 +701,12 @@ QQuickMenu *QQuickMenuBar::menuAt(int index) const
void QQuickMenuBar::addMenu(QQuickMenu *menu)
{
Q_D(QQuickMenuBar);
- addItem(d->createItem(menu));
+ if (d->menuIndex(menu) >= 0) {
+ qmlWarning(this) << "cannot add menu: '" << menu->title() << "' is already in the MenuBar.";
+ return;
+ }
+
+ d->insertMenu(count(), menu, d->createMenuBarItem(menu));
}
/*!
@@ -321,54 +717,52 @@ void QQuickMenuBar::addMenu(QQuickMenu *menu)
void QQuickMenuBar::insertMenu(int index, QQuickMenu *menu)
{
Q_D(QQuickMenuBar);
- insertItem(index, d->createItem(menu));
+ if (d->menuIndex(menu) >= 0) {
+ qmlWarning(this) << "cannot insert menu: '" << menu->title() << "' is already in the MenuBar.";
+ return;
+ }
+
+ d->insertMenu(index, menu, d->createMenuBarItem(menu));
}
/*!
\qmlmethod void QtQuick.Controls::MenuBar::removeMenu(Menu menu)
- Removes and destroys the specified \a menu.
+ Removes specified \a menu. If the menu is \l {QQuickMenu::popup(QQmlV4Function *)}{open},
+ it will first be \l {QQuickMenu::dismiss()}{dismissed.}
+ The \a menu will eventually be deleted by the garbage collector when the
+ application no longer holds any QML references to it.
*/
void QQuickMenuBar::removeMenu(QQuickMenu *menu)
{
Q_D(QQuickMenuBar);
- if (!menu)
+ const int index = d->menuIndex(menu);
+ if (index < 0) {
+ qmlWarning(this) << "cannot remove menu: '" << menu->title() << "' is not in the MenuBar.";
return;
-
- const int count = d->contentModel->count();
- for (int i = 0; i < count; ++i) {
- QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(itemAt(i));
- if (!item || item->menu() != menu)
- continue;
-
- removeItem(item);
- break;
}
- menu->deleteLater();
+ d->takeMenu(index);
}
/*!
\qmlmethod Menu QtQuick.Controls::MenuBar::takeMenu(int index)
- Removes and returns the menu at \a index.
-
- \note The ownership of the item is transferred to the caller.
+ Removes and returns the menu at \a index. If the menu is
+ \l {QQuickMenu::popup(QQmlV4Function *)}{open}, it will first be
+ \l {QQuickMenu::dismiss()}{dismissed.}
+ The menu will eventually be deleted by the garbage collector when the
+ application no longer holds any QML references to it.
*/
QQuickMenu *QQuickMenuBar::takeMenu(int index)
{
Q_D(QQuickMenuBar);
- QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(itemAt(index));
- if (!item)
- return nullptr;
-
- QQuickMenu *menu = item->menu();
- if (!menu)
+ if (index < 0 || index > count() - 1) {
+ qmlWarning(this) << "index out of range: " << index;
return nullptr;
+ }
- d->removeItem(index, item);
- item->deleteLater();
- return menu;
+ return d->takeMenu(index);
}
/*!
@@ -488,11 +882,12 @@ void QQuickMenuBar::keyPressEvent(QKeyEvent *event)
switch (event->key()) {
case Qt::Key_Up:
- d->toggleCurrentMenu(false, false);
+ d->closeCurrentMenu();
break;
case Qt::Key_Down:
- d->toggleCurrentMenu(true, true);
+ d->openCurrentMenu();
+ d->activateMenuItem(0);
break;
case Qt::Key_Left:
@@ -517,7 +912,8 @@ void QQuickMenuBar::keyPressEvent(QKeyEvent *event)
if (auto *item = qobject_cast<QQuickMenuBarItem *>(d->itemAt(i))) {
if (item->shortcut() == mnemonic) {
d->activateItem(item);
- d->toggleCurrentMenu(true, true);
+ d->openCurrentMenu();
+ d->activateMenuItem(0);
}
}
}
@@ -550,7 +946,7 @@ void QQuickMenuBar::hoverLeaveEvent(QHoverEvent *event)
{
Q_D(QQuickMenuBar);
QQuickContainer::hoverLeaveEvent(event);
- if (!d->popupMode && d->currentItem)
+ if (!d->currentMenuOpen && d->currentItem)
d->activateItem(nullptr);
}
@@ -573,6 +969,10 @@ void QQuickMenuBar::itemChange(QQuickItem::ItemChange change, const QQuickItem::
d->windowContentItem->installEventFilter(this);
}
break;
+ case ItemVisibleHasChanged:
+ qCDebug(lcMenuBar) << "visibility of" << this << "changed to" << isVisible();
+ d->syncNativeMenuBarVisible();
+ break;
default:
break;
}
@@ -587,7 +987,7 @@ void QQuickMenuBar::itemAdded(int index, QQuickItem *item)
QObjectPrivate::connect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered);
QObjectPrivate::connect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered);
if (QQuickMenu *menu = menuBarItem->menu())
- QObjectPrivate::connect(menu, &QQuickPopup::aboutToHide, d, &QQuickMenuBarPrivate::onMenuAboutToHide);
+ connect(menu, &QQuickPopup::aboutToHide, [this, menu]{ d_func()->onMenuAboutToHide(menu); });
}
d->updateImplicitContentSize();
emit menusChanged();
@@ -608,12 +1008,19 @@ void QQuickMenuBar::itemRemoved(int index, QQuickItem *item)
QObjectPrivate::disconnect(menuBarItem, &QQuickControl::hoveredChanged, d, &QQuickMenuBarPrivate::onItemHovered);
QObjectPrivate::disconnect(menuBarItem, &QQuickMenuBarItem::triggered, d, &QQuickMenuBarPrivate::onItemTriggered);
if (QQuickMenu *menu = menuBarItem->menu())
- QObjectPrivate::disconnect(menu, &QQuickPopup::aboutToHide, d, &QQuickMenuBarPrivate::onMenuAboutToHide);
+ menu->disconnect(this);
}
d->updateImplicitContentSize();
emit menusChanged();
}
+void QQuickMenuBar::componentComplete()
+{
+ Q_D(QQuickMenuBar);
+ QQuickContainer::componentComplete();
+ d->syncNativeMenuBarVisible();
+}
+
QFont QQuickMenuBar::defaultFont() const
{
return QQuickTheme::font(QQuickTheme::MenuBar);
diff --git a/src/quicktemplates/qquickmenubar_p.h b/src/quicktemplates/qquickmenubar_p.h
index daa6bf362b..f053ff6b49 100644
--- a/src/quicktemplates/qquickmenubar_p.h
+++ b/src/quicktemplates/qquickmenubar_p.h
@@ -35,6 +35,7 @@ class Q_QUICKTEMPLATES2_EXPORT QQuickMenuBar : public QQuickContainer
public:
explicit QQuickMenuBar(QQuickItem *parent = nullptr);
+ ~QQuickMenuBar() override;
QQmlComponent *delegate() const;
void setDelegate(QQmlComponent *delegate);
@@ -61,6 +62,8 @@ protected:
void itemMoved(int index, QQuickItem *item) override;
void itemRemoved(int index, QQuickItem *item) override;
+ void componentComplete() override;
+
QFont defaultFont() const override;
#if QT_CONFIG(accessibility)
diff --git a/src/quicktemplates/qquickmenubar_p_p.h b/src/quicktemplates/qquickmenubar_p_p.h
index f9a8acbd3d..98b234e1c8 100644
--- a/src/quicktemplates/qquickmenubar_p_p.h
+++ b/src/quicktemplates/qquickmenubar_p_p.h
@@ -19,6 +19,7 @@
#include <QtQuickTemplates2/private/qquickcontainer_p_p.h>
#include <QtCore/qpointer.h>
+#include <QtGui/qpa/qplatformmenu.h>
QT_BEGIN_NAMESPACE
@@ -38,19 +39,36 @@ public:
QQmlListProperty<QQuickMenu> menus();
QQmlListProperty<QObject> contentData();
- QQuickItem *beginCreateItem(QQuickMenu *menu);
- void completeCreateItem();
+ QQuickItem *createItemFromDelegate();
+ QQuickMenuBarItem *createMenuBarItem(QQuickMenu *menu);
- QQuickItem *createItem(QQuickMenu *menu);
+ void openCurrentMenu();
+ void closeCurrentMenu();
+ void activateMenuItem(int index);
- void toggleCurrentMenu(bool visible, bool activate);
void activateItem(QQuickMenuBarItem *item);
void activateNextItem();
void activatePreviousItem();
void onItemHovered();
void onItemTriggered();
- void onMenuAboutToHide();
+ void onMenuAboutToHide(QQuickMenu *menu);
+
+ void insertMenu(int index, QQuickMenu *menu, QQuickMenuBarItem *delegateItem);
+ QQuickMenu *takeMenu(int index);
+ void insertNativeMenu(QQuickMenu *menu);
+ void removeNativeMenu(QQuickMenu *menu);
+ void syncMenuBarItemVisibilty(QQuickMenuBarItem *menuBarItem);
+
+ QWindow *window() const;
+ int menuIndex(QQuickMenu *menu) const;
+
+ QPlatformMenuBar *nativeHandle() const;
+ bool useNativeMenuBar() const;
+ bool useNativeMenu(const QQuickMenu *menu) const;
+ void syncNativeMenuBarVisible();
+ void createNativeMenuBar();
+ void removeNativeMenuBar();
qreal getContentWidth() const override;
qreal getContentHeight() const override;
@@ -67,12 +85,15 @@ public:
QPalette defaultPalette() const override;
- bool popupMode = false;
- bool triggering = false;
+ bool closingCurrentMenu = false;
bool altPressed = false;
+ bool currentMenuOpen = false;
QQmlComponent *delegate = nullptr;
QPointer<QQuickMenuBarItem> currentItem;
QPointer<QQuickItem> windowContentItem;
+
+private:
+ std::unique_ptr<QPlatformMenuBar> handle;
};
QT_END_NAMESPACE
diff --git a/src/quicktemplates/qquickmenubaritem.cpp b/src/quicktemplates/qquickmenubaritem.cpp
index cc5fb83e40..68aff1e62d 100644
--- a/src/quicktemplates/qquickmenubaritem.cpp
+++ b/src/quicktemplates/qquickmenubaritem.cpp
@@ -92,6 +92,7 @@ QQuickMenuBarItem::QQuickMenuBarItem(QQuickItem *parent)
: QQuickAbstractButton(*(new QQuickMenuBarItemPrivate), parent)
{
setFocusPolicy(Qt::NoFocus);
+ d_func()->setSizePolicy(QLayoutPolicy::Fixed, QLayoutPolicy::Fixed);
}
/*!
diff --git a/src/quicktemplates/qquickmenuitem.cpp b/src/quicktemplates/qquickmenuitem.cpp
index c5b0ea2753..32a0719150 100644
--- a/src/quicktemplates/qquickmenuitem.cpp
+++ b/src/quicktemplates/qquickmenuitem.cpp
@@ -3,7 +3,7 @@
#include "qquickmenuitem_p.h"
#include "qquickmenuitem_p_p.h"
-#include "qquickmenu_p.h"
+#include "qquickmenu_p_p.h"
#include "qquickdeferredexecute_p_p.h"
#include <QtGui/qpa/qplatformtheme.h>
@@ -56,6 +56,44 @@ QT_BEGIN_NAMESPACE
\sa {Customizing Menu}, Menu, {Menu Controls}
*/
+/*!
+ \qmlproperty bool QtQuick.Controls::MenuItem::textPadding
+ \readonly
+ \since 6.8
+
+ This property holds the maximum \l implicitTextPadding found
+ among all the menu items inside the same \l menu.
+
+ This property can be used by the style to ensure that all MenuItems
+ inside the same Menu end up aligned with respect to the \l text.
+
+ A \l Menu can consist of meny different MenuItems, some can be checkable,
+ some can have an icon, and some will just contain text. And very often,
+ a style wants to make sure that the text inside all of them ends up
+ left-aligned (or right-aligned for \l mirrored items).
+ By letting each MenuItem assign its own minimum text padding to
+ \l implicitTextPadding (taking icons and checkmarks into account), but
+ using \l textPadding to actually position the \l text, all MenuItems should
+ end up being aligned
+
+ In order for this to work, all MenuItems should set \l implicitTextPadding
+ to be the minimum space needed from the left edge of the \l contentItem to
+ the text.
+
+ \sa implicitTextPadding
+*/
+
+/*!
+ \qmlproperty bool QtQuick.Controls::MenuItem::implicitTextPadding
+ \since 6.8
+
+ This property holds the minimum space needed from the left edge of the
+ \l contentItem to the text. It's used to calculate a common \l textPadding
+ among all the MenuItems inside a \l Menu.
+
+ \sa textPadding
+*/
+
void QQuickMenuItemPrivate::setMenu(QQuickMenu *newMenu)
{
Q_Q(QQuickMenuItem);
@@ -240,6 +278,26 @@ QFont QQuickMenuItem::defaultFont() const
return QQuickTheme::font(QQuickTheme::Menu);
}
+qreal QQuickMenuItem::implicitTextPadding() const
+{
+ return d_func()->implicitTextPadding;
+}
+
+void QQuickMenuItem::setImplicitTextPadding(qreal newImplicitTextPadding)
+{
+ Q_D(QQuickMenuItem);
+ if (qFuzzyCompare(d->implicitTextPadding, newImplicitTextPadding))
+ return;
+ d->implicitTextPadding = newImplicitTextPadding;
+ emit implicitTextPaddingChanged();
+}
+
+qreal QQuickMenuItem::textPadding() const
+{
+ Q_D(const QQuickMenuItem);
+ return d->menu ? QQuickMenuPrivate::get(d->menu)->textPadding : 0;
+}
+
#if QT_CONFIG(accessibility)
QAccessible::Role QQuickMenuItem::accessibleRole() const
{
@@ -247,6 +305,25 @@ QAccessible::Role QQuickMenuItem::accessibleRole() const
}
#endif
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QQuickMenuItem *menuItem)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ if (!menuItem) {
+ debug << "QQuickMenuItem(nullptr)";
+ return debug;
+ }
+
+ debug << menuItem->metaObject()->className() << '(' << static_cast<const void *>(menuItem);
+ if (!menuItem->objectName().isEmpty())
+ debug << ", name=" << menuItem->objectName();
+ debug << ", text=" << menuItem->text();
+ debug << ')';
+ return debug;
+}
+#endif // QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
#include "moc_qquickmenuitem_p.cpp"
diff --git a/src/quicktemplates/qquickmenuitem_p.h b/src/quicktemplates/qquickmenuitem_p.h
index fb99dc2502..786b6f8ae6 100644
--- a/src/quicktemplates/qquickmenuitem_p.h
+++ b/src/quicktemplates/qquickmenuitem_p.h
@@ -33,6 +33,8 @@ class Q_QUICKTEMPLATES2_EXPORT QQuickMenuItem : public QQuickAbstractButton
Q_PROPERTY(QQuickItem *arrow READ arrow WRITE setArrow NOTIFY arrowChanged FINAL REVISION(2, 3))
Q_PROPERTY(QQuickMenu *menu READ menu NOTIFY menuChanged FINAL REVISION(2, 3))
Q_PROPERTY(QQuickMenu *subMenu READ subMenu NOTIFY subMenuChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(qreal implicitTextPadding READ implicitTextPadding WRITE setImplicitTextPadding NOTIFY implicitTextPaddingChanged REVISION(6, 8))
+ Q_PROPERTY(qreal textPadding READ textPadding NOTIFY textPaddingChanged REVISION(6, 8))
Q_CLASSINFO("DeferredPropertyNames", "arrow,background,contentItem,indicator")
QML_NAMED_ELEMENT(MenuItem)
QML_ADDED_IN_VERSION(2, 0)
@@ -50,6 +52,10 @@ public:
QQuickMenu *menu() const;
QQuickMenu *subMenu() const;
+ qreal textPadding() const;
+ qreal implicitTextPadding() const;
+ void setImplicitTextPadding(qreal newImplicitTextPadding);
+
Q_SIGNALS:
void triggered();
void highlightedChanged();
@@ -57,6 +63,8 @@ Q_SIGNALS:
Q_REVISION(2, 3) void arrowChanged();
Q_REVISION(2, 3) void menuChanged();
Q_REVISION(2, 3) void subMenuChanged();
+ Q_REVISION(6, 8) void implicitTextPaddingChanged();
+ Q_REVISION(6, 8) void textPaddingChanged();
protected:
void componentComplete() override;
@@ -72,6 +80,10 @@ private:
Q_DECLARE_PRIVATE(QQuickMenuItem)
};
+#ifndef QT_NO_DEBUG_STREAM
+Q_QUICKTEMPLATES2_EXPORT QDebug operator<<(QDebug debug, const QQuickMenuItem *menuItem);
+#endif
+
QT_END_NAMESPACE
#endif // QQUICKMENUITEM_P_H
diff --git a/src/quicktemplates/qquickmenuitem_p_p.h b/src/quicktemplates/qquickmenuitem_p_p.h
index 63bcfa33f6..3ef4981570 100644
--- a/src/quicktemplates/qquickmenuitem_p_p.h
+++ b/src/quicktemplates/qquickmenuitem_p_p.h
@@ -48,6 +48,7 @@ public:
QQuickDeferredPointer<QQuickItem> arrow;
QQuickMenu *menu = nullptr;
QQuickMenu *subMenu = nullptr;
+ qreal implicitTextPadding;
};
QT_END_NAMESPACE
diff --git a/src/quicktemplates/qquicknativeicon.cpp b/src/quicktemplates/qquicknativeicon.cpp
new file mode 100644
index 0000000000..dfc8a4cc7e
--- /dev/null
+++ b/src/quicktemplates/qquicknativeicon.cpp
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquicknativeicon_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QUrl QQuickNativeIcon::source() const
+{
+ return m_source;
+}
+
+void QQuickNativeIcon::setSource(const QUrl& source)
+{
+ m_source = source;
+}
+
+QString QQuickNativeIcon::name() const
+{
+ return m_name;
+}
+
+void QQuickNativeIcon::setName(const QString& name)
+{
+ m_name = name;
+}
+
+bool QQuickNativeIcon::isMask() const
+{
+ return m_mask;
+}
+
+void QQuickNativeIcon::setMask(bool mask)
+{
+ m_mask = mask;
+}
+
+bool QQuickNativeIcon::operator==(const QQuickNativeIcon &other) const
+{
+ return m_source == other.m_source && m_name == other.m_name && m_mask == other.m_mask;
+}
+
+bool QQuickNativeIcon::operator!=(const QQuickNativeIcon &other) const
+{
+ return !(*this == other);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicknativeicon_p.cpp"
diff --git a/src/quicktemplates/qquicknativeicon_p.h b/src/quicktemplates/qquicknativeicon_p.h
new file mode 100644
index 0000000000..db0625954a
--- /dev/null
+++ b/src/quicktemplates/qquicknativeicon_p.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQUICKNATIVEICON_P_H
+#define QQUICKNATIVEICON_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 <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+
+#include <QtQml/qqmlengine.h>
+#include <QtCore/private/qglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+
+class QQuickNativeIcon
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ Q_PROPERTY(QUrl source READ source WRITE setSource FINAL)
+ Q_PROPERTY(QString name READ name WRITE setName FINAL)
+ Q_PROPERTY(bool mask READ isMask WRITE setMask FINAL)
+
+public:
+ QUrl source() const;
+ void setSource(const QUrl &source);
+
+ QString name() const;
+ void setName(const QString &name);
+
+ bool isMask() const;
+ void setMask(bool mask);
+
+ bool operator==(const QQuickNativeIcon &other) const;
+ bool operator!=(const QQuickNativeIcon &other) const;
+
+private:
+ bool m_mask = false;
+ QUrl m_source;
+ QString m_name;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKNATIVEICON_P_H
diff --git a/src/quicktemplates/qquicknativeiconloader.cpp b/src/quicktemplates/qquicknativeiconloader.cpp
new file mode 100644
index 0000000000..8b5dd54257
--- /dev/null
+++ b/src/quicktemplates/qquicknativeiconloader.cpp
@@ -0,0 +1,66 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquicknativeiconloader_p.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmetaobject.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickNativeIconLoader::QQuickNativeIconLoader(int slot, QObject *parent)
+ : m_parent(parent),
+ m_slot(slot),
+ m_enabled(false)
+{
+ Q_ASSERT(slot != -1 && parent);
+}
+
+bool QQuickNativeIconLoader::isEnabled() const
+{
+ return m_enabled;
+}
+
+void QQuickNativeIconLoader::setEnabled(bool enabled)
+{
+ m_enabled = enabled;
+ if (m_enabled)
+ loadIcon();
+}
+
+QIcon QQuickNativeIconLoader::toQIcon() const
+{
+ const QIcon fallback = QPixmap::fromImage(image());
+ return QIcon::fromTheme(m_icon.name(), fallback);
+}
+
+QQuickIcon QQuickNativeIconLoader::icon() const
+{
+ return m_icon;
+}
+
+void QQuickNativeIconLoader::setIcon(const QQuickIcon &icon)
+{
+ m_icon = icon;
+ if (m_enabled)
+ loadIcon();
+}
+
+void QQuickNativeIconLoader::loadIcon()
+{
+ if (m_icon.source().isEmpty()) {
+ clear(m_parent);
+ } else {
+ load(qmlEngine(m_parent), m_icon.source());
+ if (m_slot != -1 && isLoading()) {
+ connectFinished(m_parent, m_slot);
+ m_slot = -1;
+ }
+ }
+
+ if (!isLoading())
+ m_parent->metaObject()->method(m_slot).invoke(m_parent);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates/qquicknativeiconloader_p.h b/src/quicktemplates/qquicknativeiconloader_p.h
new file mode 100644
index 0000000000..063178dc47
--- /dev/null
+++ b/src/quicktemplates/qquicknativeiconloader_p.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQUICKNATIVEICONLOADER_P_H
+#define QQUICKNATIVEICONLOADER_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 <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+#include <QtGui/qicon.h>
+#include <QtQuick/private/qquickpixmap_p.h>
+#include <QtQuickTemplates2/private/qquickicon_p.h>
+
+#include "qquicknativeicon_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+
+class QQuickNativeIconLoader : public QQuickPixmap
+{
+public:
+ QQuickNativeIconLoader(int slot, QObject *parent);
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ QIcon toQIcon() const;
+
+ QQuickIcon icon() const;
+ void setIcon(const QQuickIcon &icon);
+
+private:
+ void loadIcon();
+
+ QObject *m_parent;
+ int m_slot;
+ bool m_enabled;
+ QQuickIcon m_icon;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKNATIVEICONLOADER_P_H
diff --git a/src/quicktemplates/qquicknativemenuitem.cpp b/src/quicktemplates/qquicknativemenuitem.cpp
new file mode 100644
index 0000000000..66f67832b7
--- /dev/null
+++ b/src/quicktemplates/qquicknativemenuitem.cpp
@@ -0,0 +1,329 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquickmenuitem_p.h"
+
+#include <QtCore/qloggingcategory.h>
+//#include <QtGui/qicon.h>
+//#if QT_CONFIG(shortcut)
+//#include <QtGui/qkeysequence.h>
+//#endif
+#include <QtGui/qpa/qplatformmenu.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+//#include <QtQuickTemplates2/private/qquickshortcutcontext_p_p.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p_p.h>
+#include <QtQuickTemplates2/private/qquickaction_p.h>
+#include <QtQuickTemplates2/private/qquickmenu_p_p.h>
+#include <QtQuickTemplates2/private/qquickmenuseparator_p.h>
+#include <QtQuickTemplates2/private/qquicknativeiconloader_p.h>
+#include <QtQuickTemplates2/private/qquicknativemenuitem_p.h>
+#include <QtQuickTemplates2/private/qquickshortcutcontext_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_STATIC_LOGGING_CATEGORY(lcNativeMenuItem, "qt.quick.controls.nativemenuitem")
+
+/*!
+ \class QQuickNativeMenuItem
+ \brief A native menu item.
+ \since 6.7
+ \internal
+
+ Creates a native menu item from an Action/MenuItem/Menu,
+ and syncs the properties and signals. It can also represent a
+ MenuSeparator.
+
+ \sa Menu, Action
+*/
+
+QQuickNativeMenuItem *QQuickNativeMenuItem::createFromNonNativeItem(
+ QQuickMenu *parentMenu, QQuickItem *nonNativeItem)
+{
+ auto *menuItem = qobject_cast<QQuickMenuItem *>(nonNativeItem);
+ Type type = Type::Unknown;
+ if (menuItem) {
+ if (menuItem->action()) {
+ type = Type::Action;
+ } else if (menuItem->subMenu()) {
+ type = Type::SubMenu;
+ } else {
+ // It's a plain MenuItem, rather than a MenuItem created by us for an Action or Menu.
+ type = Type::MenuItem;
+ }
+ } else if (qobject_cast<QQuickMenuSeparator *>(nonNativeItem)) {
+ type = Type::Separator;
+ }
+
+ std::unique_ptr<QQuickNativeMenuItem> nativeMenuItemPtr(new QQuickNativeMenuItem(
+ parentMenu, nonNativeItem, type));
+ if (type == Type::Unknown) {
+ // It's not a Menu/Action/MenuSeparator that we're dealing with, but we still need
+ // to create the QQuickNativeMenu item for it so that our container has the same
+ // indices as the menu's contentModel.
+ return nativeMenuItemPtr.release();
+ }
+
+ qCDebug(lcNativeMenuItem) << "attemping to create native menu item for"
+ << nativeMenuItemPtr->debugText();
+ auto *parentMenuPrivate = QQuickMenuPrivate::get(parentMenu);
+ nativeMenuItemPtr->m_handle.reset(parentMenuPrivate->handle->createMenuItem());
+ if (!nativeMenuItemPtr->m_handle)
+ nativeMenuItemPtr->m_handle.reset(QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem());
+ if (!nativeMenuItemPtr->m_handle)
+ return nullptr;
+
+ auto *nativeMenuItem = nativeMenuItemPtr.release();
+ switch (type) {
+ case Type::Action:
+ // Ensure that the action is triggered when the user clicks on a native menu item.
+ connect(nativeMenuItem->m_handle.get(), &QPlatformMenuItem::activated,
+ nativeMenuItem->action(), [nativeMenuItem, parentMenu](){
+ nativeMenuItem->action()->trigger(parentMenu);
+ });
+ // Handle programmatic changes in the Action.
+ connect(nativeMenuItem->action(), &QQuickAction::textChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(nativeMenuItem->action(), &QQuickAction::iconChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(nativeMenuItem->action(), &QQuickAction::enabledChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(nativeMenuItem->action(), &QQuickAction::checkedChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(nativeMenuItem->action(), &QQuickAction::checkableChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ break;
+ case Type::SubMenu:
+ nativeMenuItem->m_handle->setMenu(QQuickMenuPrivate::get(
+ nativeMenuItem->subMenu())->handle.get());
+
+ // Handle programmatic changes in the Menu.
+ connect(nativeMenuItem->subMenu(), &QQuickMenu::enabledChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(nativeMenuItem->subMenu(), &QQuickMenu::titleChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ break;
+ case Type::MenuItem:
+ // Ensure that the MenuItem is clicked when the user clicks on a native menu item.
+ connect(nativeMenuItem->m_handle.get(), &QPlatformMenuItem::activated,
+ menuItem, [menuItem](){
+ // This changes the checked state, which we need when syncing but also to ensure that
+ // the user can still use MenuItem's API even though they can't actually interact with it.
+ menuItem->toggle();
+ // The same applies here: allow users to respond to the MenuItem's clicked signal.
+ QQuickAbstractButtonPrivate::get(menuItem)->click();
+ });
+ // Handle programmatic changes in the MenuItem.
+ connect(menuItem, &QQuickMenuItem::textChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(menuItem, &QQuickMenuItem::iconChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(menuItem, &QQuickMenuItem::enabledChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(menuItem, &QQuickMenuItem::checkedChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ connect(menuItem, &QQuickMenuItem::checkableChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
+ break;
+ case Type::Separator:
+ case Type::Unknown:
+ break;
+ }
+
+ return nativeMenuItem;
+}
+
+QQuickNativeMenuItem::QQuickNativeMenuItem(QQuickMenu *parentMenu, QQuickItem *nonNativeItem,
+ QQuickNativeMenuItem::Type type)
+ : QObject(parentMenu)
+ , m_parentMenu(parentMenu)
+ , m_nonNativeItem(nonNativeItem)
+ , m_type(type)
+{
+}
+
+QQuickNativeMenuItem::~QQuickNativeMenuItem()
+{
+ qCDebug(lcNativeMenuItem) << "destroying" << this << debugText();
+}
+
+QQuickAction *QQuickNativeMenuItem::action() const
+{
+ return m_type == Type::Action ? qobject_cast<QQuickMenuItem *>(m_nonNativeItem)->action() : nullptr;
+}
+
+QQuickMenu *QQuickNativeMenuItem::subMenu() const
+{
+ return m_type == Type::SubMenu ? qobject_cast<QQuickMenuItem *>(m_nonNativeItem)->subMenu() : nullptr;
+}
+
+QQuickMenuSeparator *QQuickNativeMenuItem::separator() const
+{
+ return m_type == Type::Separator ? qobject_cast<QQuickMenuSeparator *>(m_nonNativeItem) : nullptr;
+}
+
+QPlatformMenuItem *QQuickNativeMenuItem::handle() const
+{
+ return m_handle.get();
+}
+
+void QQuickNativeMenuItem::sync()
+{
+ if (m_type == Type::Unknown)
+ return;
+
+ if (m_syncing)
+ return;
+
+ QScopedValueRollback recursionGuard(m_syncing, true);
+
+ const auto *action = this->action();
+ const auto *separator = this->separator();
+ auto *subMenu = this->subMenu();
+ auto *menuItem = qobject_cast<QQuickMenuItem *>(m_nonNativeItem);
+
+ // Store the values in variables so that we can use it in the debug output below.
+ const bool enabled = action ? action->isEnabled()
+ : subMenu ? subMenu->isEnabled()
+ : menuItem && menuItem->isEnabled();
+ m_handle->setEnabled(enabled);
+// m_handle->setVisible(isVisible());
+
+ const bool isSeparator = separator != nullptr;
+ m_handle->setIsSeparator(isSeparator);
+
+ const bool checkable = action ? action->isCheckable() : menuItem && menuItem->isCheckable();
+ m_handle->setCheckable(checkable);
+
+ const bool checked = action ? action->isChecked() : menuItem && menuItem->isChecked();
+ m_handle->setChecked(checked);
+
+ m_handle->setRole(QPlatformMenuItem::TextHeuristicRole);
+
+ const QString text = action ? action->text()
+ : subMenu ? subMenu->title()
+ : menuItem ? menuItem->text() : QString();
+ m_handle->setText(text);
+
+// m_handle->setFont(m_font);
+// m_handle->setHasExclusiveGroup(m_group && m_group->isExclusive());
+ m_handle->setHasExclusiveGroup(false);
+
+ const QQuickIcon icon = effectiveIcon();
+ const auto *menuPrivate = QQuickMenuPrivate::get(m_parentMenu);
+ const auto *window = qGuiApp->topLevelWindows().first();
+ // We should reload the icon if the window's DPR has changed, regardless if its properties have changed.
+ // We can't check for ItemDevicePixelRatioHasChanged in QQuickMenu::itemChange,
+ // because that isn't sent when the menu isn't visible, and will never
+ // be sent for native menus. We instead store lastDevicePixelRatio in QQuickMenu
+ // (to avoid storing it for each menu item) and set it whenever it's opened.
+ const bool dprChanged = !qFuzzyCompare(window->devicePixelRatio(), menuPrivate->lastDevicePixelRatio);
+ if (!icon.isEmpty() && (icon != iconLoader()->icon() || dprChanged)) {
+ // This will load the icon, which will call sync() recursively, hence the m_syncing check.
+ reloadIcon();
+ }
+
+ if (subMenu) {
+ // Sync first as dynamically created menus may need to get the handle recreated.
+ auto *subMenuPrivate = QQuickMenuPrivate::get(subMenu);
+ subMenuPrivate->syncWithNativeMenu();
+ if (subMenuPrivate->handle)
+ m_handle->setMenu(subMenuPrivate->handle.get());
+ }
+
+#if QT_CONFIG(shortcut)
+ if (action)
+ m_handle->setShortcut(action->shortcut());
+#endif
+
+ if (m_parentMenu) {
+ auto *menuPrivate = QQuickMenuPrivate::get(m_parentMenu);
+ if (menuPrivate->handle)
+ menuPrivate->handle->syncMenuItem(m_handle.get());
+ }
+
+ qCDebug(lcNativeMenuItem) << "sync called on" << debugText() << "handle" << m_handle.get()
+ << "enabled:" << enabled << "isSeparator" << isSeparator << "checkable" << checkable
+ << "checked" << checked << "text" << text;
+}
+
+QQuickIcon QQuickNativeMenuItem::effectiveIcon() const
+{
+ if (const auto *action = this->action())
+ return action->icon();
+ if (const auto *subMenu = this->subMenu())
+ return subMenu->icon();
+ if (const auto *menuItem = qobject_cast<QQuickMenuItem *>(m_nonNativeItem))
+ return menuItem->icon();
+ return {};
+}
+
+QQuickNativeIconLoader *QQuickNativeMenuItem::iconLoader() const
+{
+ if (!m_iconLoader) {
+ QQuickNativeMenuItem *that = const_cast<QQuickNativeMenuItem *>(this);
+ static int slot = staticMetaObject.indexOfSlot("updateIcon()");
+ m_iconLoader = new QQuickNativeIconLoader(slot, that);
+ // Qt Labs Platform's QQuickMenuItem would call m_iconLoader->setEnabled(m_complete) here,
+ // but since QQuickMenuPrivate::maybeCreateAndInsertNativeItem asserts that the menu's
+ // completed loading, we can just set it to true.
+ m_iconLoader->setEnabled(true);
+ }
+ return m_iconLoader;
+}
+
+void QQuickNativeMenuItem::reloadIcon()
+{
+ iconLoader()->setIcon(effectiveIcon());
+ m_handle->setIcon(iconLoader()->toQIcon());
+}
+
+void QQuickNativeMenuItem::updateIcon()
+{
+ sync();
+}
+
+void QQuickNativeMenuItem::addShortcut()
+{
+#if QT_CONFIG(shortcut)
+ const auto *action = this->action();
+ const QKeySequence sequence = action ? action->shortcut() : QKeySequence();
+ if (!sequence.isEmpty() && action->isEnabled()) {
+ m_shortcutId = QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(this, sequence,
+ Qt::WindowShortcut, QQuickShortcutContext::matcher);
+ } else {
+ m_shortcutId = -1;
+ }
+#endif
+}
+
+void QQuickNativeMenuItem::removeShortcut()
+{
+#if QT_CONFIG(shortcut)
+ if (m_shortcutId == -1)
+ return;
+
+ QKeySequence sequence;
+ switch (m_type) {
+ case Type::Action:
+ sequence = action()->shortcut();
+ break;
+ default:
+ // TODO
+ break;
+ }
+
+ QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(m_shortcutId, this, sequence);
+#endif
+}
+
+QString QQuickNativeMenuItem::debugText() const
+{
+ switch (m_type) {
+ case Type::Action:
+ return QString::fromLatin1("Action(text = %1)").arg(action()->text());
+ case Type::SubMenu:
+ return QString::fromLatin1("Sub-menu(title = %1)").arg(subMenu()->title());
+ case Type::MenuItem:
+ return QString::fromLatin1("MenuItem(text = %1)").arg(
+ qobject_cast<QQuickMenuItem *>(m_nonNativeItem)->text());
+ case Type::Separator:
+ return QStringLiteral("Separator");
+ case Type::Unknown:
+ return QStringLiteral("(Unknown)");
+ }
+
+ Q_UNREACHABLE();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicknativemenuitem_p.cpp"
diff --git a/src/quicktemplates/qquicknativemenuitem_p.h b/src/quicktemplates/qquicknativemenuitem_p.h
new file mode 100644
index 0000000000..421d84df29
--- /dev/null
+++ b/src/quicktemplates/qquicknativemenuitem_p.h
@@ -0,0 +1,81 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQUICKNATIVEMENUITEM_P_H
+#define QQUICKNATIVEMENUITEM_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 <QtCore/qobject.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+#include <QtQuickTemplates2/private/qquickicon_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAction;
+class QQuickNativeIconLoader;
+class QQuickMenu;
+class QQuickMenuSeparator;
+class QPlatformMenuItem;
+
+class Q_QUICKTEMPLATES2_EXPORT QQuickNativeMenuItem : public QObject
+{
+ Q_OBJECT
+
+public:
+ static QQuickNativeMenuItem *createFromNonNativeItem(
+ QQuickMenu *parentMenu, QQuickItem *nonNativeItem);
+ ~QQuickNativeMenuItem();
+
+ QQuickAction *action() const;
+ QQuickMenu *subMenu() const;
+ QQuickMenuSeparator *separator() const;
+ QPlatformMenuItem *handle() const;
+ void sync();
+
+ QQuickIcon effectiveIcon() const;
+ QQuickNativeIconLoader *iconLoader() const;
+ void reloadIcon();
+
+ QString debugText() const;
+
+private Q_SLOTS:
+ void updateIcon();
+
+private:
+ enum class Type {
+ Unknown,
+ // It's an Action or a MenuItem with an Action.
+ Action,
+ // It's a MenuItem without an Action.
+ MenuItem,
+ Separator,
+ SubMenu
+ };
+
+ explicit QQuickNativeMenuItem(QQuickMenu *parentMenu, QQuickItem *nonNativeItem, Type type);
+
+ void addShortcut();
+ void removeShortcut();
+
+ QQuickMenu *m_parentMenu = nullptr;
+ QQuickItem *m_nonNativeItem = nullptr;
+ Type m_type = Type::Unknown;
+ mutable QQuickNativeIconLoader *m_iconLoader = nullptr;
+ std::unique_ptr<QPlatformMenuItem> m_handle = nullptr;
+ int m_shortcutId = -1;
+ bool m_syncing = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKNATIVEMENUITEM_P_H
diff --git a/src/quicktemplates/qquickoverlay.cpp b/src/quicktemplates/qquickoverlay.cpp
index 36fa669d22..8588a19220 100644
--- a/src/quicktemplates/qquickoverlay.cpp
+++ b/src/quicktemplates/qquickoverlay.cpp
@@ -513,10 +513,7 @@ bool QQuickOverlay::eventFilter(QObject *object, QEvent *event)
event->accept();
// Since we eat the event, QQuickWindow::event never sees it to clean up the
// grabber states. So we have to do so explicitly.
- if (QQuickWindow *window = parentItem() ? parentItem()->window() : nullptr) {
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
- d->clearGrabbers(static_cast<QPointerEvent *>(event));
- }
+ d->deliveryAgentPrivate()->clearGrabbers(static_cast<QPointerEvent *>(event));
return true;
#endif
diff --git a/src/quicktemplates/qquickpage.cpp b/src/quicktemplates/qquickpage.cpp
index 55c6d3a178..9f19f5bae3 100644
--- a/src/quicktemplates/qquickpage.cpp
+++ b/src/quicktemplates/qquickpage.cpp
@@ -280,6 +280,11 @@ void QQuickPage::setTitle(const QString &title)
emit titleChanged();
}
+void QQuickPage::resetTitle()
+{
+ setTitle(QString());
+}
+
/*!
\qmlproperty Item QtQuick.Controls::Page::header
diff --git a/src/quicktemplates/qquickpage_p.h b/src/quicktemplates/qquickpage_p.h
index 02725cc7c5..7eaa443146 100644
--- a/src/quicktemplates/qquickpage_p.h
+++ b/src/quicktemplates/qquickpage_p.h
@@ -25,7 +25,7 @@ class QQuickPagePrivate;
class Q_QUICKTEMPLATES2_EXPORT QQuickPage : public QQuickPane
{
Q_OBJECT
- Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged FINAL)
+ Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged RESET resetTitle FINAL)
Q_PROPERTY(QQuickItem *header READ header WRITE setHeader NOTIFY headerChanged FINAL)
Q_PROPERTY(QQuickItem *footer READ footer WRITE setFooter NOTIFY footerChanged FINAL)
// 2.5 (Qt 5.12)
@@ -42,6 +42,7 @@ public:
QString title() const;
void setTitle(const QString &title);
+ void resetTitle();
QQuickItem *header() const;
void setHeader(QQuickItem *header);
diff --git a/src/quicktemplates/qquickpane.cpp b/src/quicktemplates/qquickpane.cpp
index 02f32e720e..c726eea228 100644
--- a/src/quicktemplates/qquickpane.cpp
+++ b/src/quicktemplates/qquickpane.cpp
@@ -9,7 +9,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcPane, "qt.quick.controls.pane")
+Q_STATIC_LOGGING_CATEGORY(lcPane, "qt.quick.controls.pane")
/*!
\qmltype Pane
diff --git a/src/quicktemplates/qquickpopup.cpp b/src/quicktemplates/qquickpopup.cpp
index 6aa88a465e..37ddebf6d4 100644
--- a/src/quicktemplates/qquickpopup.cpp
+++ b/src/quicktemplates/qquickpopup.cpp
@@ -5,6 +5,7 @@
#include "qquickpopup_p_p.h"
#include "qquickpopupanchors_p.h"
#include "qquickpopupitem_p_p.h"
+#include "qquickpopupwindow_p_p.h"
#include "qquickpopuppositioner_p_p.h"
#include "qquickapplicationwindow_p.h"
#include "qquickoverlay_p_p.h"
@@ -19,11 +20,13 @@
#include <QtQuick/private/qquickaccessibleattached_p.h>
#include <QtQuick/private/qquicktransition_p.h>
#include <QtQuick/private/qquickitem_p.h>
+#include <qpa/qplatformintegration.h>
+#include <private/qguiapplication_p.h>
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcDimmer, "qt.quick.controls.popup.dimmer")
-Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
+Q_STATIC_LOGGING_CATEGORY(lcDimmer, "qt.quick.controls.popup.dimmer")
+Q_STATIC_LOGGING_CATEGORY(lcQuickPopup, "qt.quick.controls.popup")
/*!
\qmltype Popup
@@ -39,8 +42,8 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
used with \l Window or \l ApplicationWindow.
\qml
- import QtQuick.Window 2.2
- import QtQuick.Controls 2.12
+ import QtQuick.Window
+ import QtQuick.Controls
ApplicationWindow {
id: window
@@ -66,10 +69,6 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
}
\endqml
- In order to ensure that a popup is displayed above other items in the
- scene, it is recommended to use ApplicationWindow. ApplicationWindow also
- provides background dimming effects.
-
Popup does not provide a layout of its own, but requires you to position
its contents, for instance by creating a \l RowLayout or a \l ColumnLayout.
@@ -121,6 +120,57 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
}
\endcode
+ \section1 Popup type
+
+ Since Qt 6.8, some popups, such as \l Menu, offer three different implementations,
+ depending on the platform. You can choose which one you prefer by setting \l popupType.
+
+ Whether a popup will be able to use the preferred type depends on the platform.
+ \c Popup.Item is supported on all platforms, but \c Popup.Window and \c Popup.Native
+ are normally only supported on desktop platforms. Additionally, if a popup is a
+ \l Menu inside a \l {Native menu bars}{native menubar}, the menu will be native as
+ well. And if the menu is a sub-menu inside another menu, the parent (or root) menu
+ will decide the type.
+
+ \section2 Showing a popup as an item
+
+ By setting \l popupType to \c Popup.Item, the popup will \e not be shown as a separate
+ window, but as an item inside the same scene as the parent. This item is parented
+ to that scene's \l{Overlay::overlay}{overlay}, and styled to look like an actual window.
+
+ This option is especially useful on platforms that doesn't support multiple windows.
+ This was also the only option before Qt 6.8.
+
+ In order to ensure that a popup is displayed above other items in the
+ scene, it is recommended to use ApplicationWindow. ApplicationWindow also
+ provides background dimming effects.
+
+ \section2 Showing a popup as a separate window
+
+ By setting \l popupType to \c Popup.Window, the popup will be shown inside a top-level
+ \l {QQuickWindow}{window} configured with the \l Qt::Popup flag. Using a window to show a
+ popup has the advantage that the popup will float on top of the parent window, and
+ can be placed outside of its geometry. The popup will otherwise look the same as when
+ using \c Popup.Item, that is, it will use the same QML delegates and styling as
+ when using \c Popup.Item.
+
+ \note If the platform doesn't support \c Popup.Window, \c Popup.Item will be used as fallback.
+
+ \section2 Showing a native popup
+
+ By setting \l popupType to \c Popup.Native, the popup will be shown using a platform
+ native popup window. This window, and all its contents, will be rendered by the
+ platform, and not by QML. This means that the QML delegates assigned to the popup
+ will \e not be used for rendering. If you for example
+ use this option on a \l Menu, it will be implemented using platform-specific
+ menu APIs. This will normally make the popup look and feel more native than for example
+ \c Popup.Window, but at the same time, suffer from platform limitations and differences
+ related to appearance and behavior. Such limitations are documented in more detail
+ in the subclasses that are affected, such as for a
+ \l {Limitations when using native menus}{Menu}).
+
+ \note If the platform doesn't support \c Popup.Native, \c Popup.Window will be used as fallback.
+
\section1 Popup Sizing
If only a single item is used within a Popup, it will resize to fit the
@@ -172,7 +222,7 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
}
\endcode
- \note The popup's \l{contentItem}{content item} gets parented to the
+ \note When using \l {Popup Items}, the popup's \l{contentItem}{content item} gets parented to the
\l{Overlay::overlay}{overlay}, and does not live within the popup's parent.
Because of that, a \l{Item::scale}{scale} applied to the tree in which
the popup lives does not apply to the visual popup. To make the popup
@@ -221,8 +271,8 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
\section1 Showing Non-Child Items in Front of Popup
- Popup sets its contentItem's
- \l{qtquick-visualcanvas-visualparent.html}{visual parent}
+ In cases where \l {Showing a popup as an item}{popup windows} are not being used,
+ Popup sets its contentItem's \l{qtquick-visualcanvas-visualparent.html}{visual parent}
to be the window's \l{Overlay::overlay}{overlay}, in order to ensure that
the popup appears in front of everything else in the scene.
In some cases, it might be useful to put an item in front of a popup,
@@ -372,6 +422,18 @@ Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
\sa closed()
*/
+QQuickItem *QQuickPopup::findParentItem() const
+{
+ QObject *obj = parent();
+ while (obj) {
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (item)
+ return item;
+ obj = obj->parent();
+ }
+ return nullptr;
+}
+
const QQuickPopup::ClosePolicy QQuickPopupPrivate::DefaultClosePolicy = QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutside;
QQuickPopupPrivate::QQuickPopupPrivate()
@@ -384,7 +446,6 @@ void QQuickPopupPrivate::init()
Q_Q(QQuickPopup);
popupItem = new QQuickPopupItem(q);
popupItem->setVisible(false);
- q->setParentItem(qobject_cast<QQuickItem *>(parent));
QObject::connect(popupItem, &QQuickControl::paddingChanged, q, &QQuickPopup::paddingChanged);
QObject::connect(popupItem, &QQuickControl::backgroundChanged, q, &QQuickPopup::backgroundChanged);
QObject::connect(popupItem, &QQuickControl::contentItemChanged, q, &QQuickPopup::contentItemChanged);
@@ -468,7 +529,16 @@ bool QQuickPopupPrivate::handlePress(QQuickItem *item, const QPointF &point, ulo
Q_UNUSED(timestamp);
pressPoint = point;
outsidePressed = !contains(point);
- outsideParentPressed = outsidePressed && parentItem && !parentItem->contains(parentItem->mapFromScene(point));
+
+ if (outsidePressed && parentItem) {
+ // Note that the parentItem (e.g a menuBarItem, in case of a MenuBar) will
+ // live inside another window when using popup windows. We therefore need to
+ // map to and from global.
+ const QPointF globalPoint = item->mapToGlobal(point);
+ const QPointF localPoint = parentItem->mapFromGlobal(globalPoint);
+ outsideParentPressed = !parentItem->contains(localPoint);
+ }
+
tryClose(point, QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent);
return blockInput(item, point);
}
@@ -530,6 +600,65 @@ bool QQuickPopupPrivate::handleHoverEvent(QQuickItem *item, QHoverEvent *event)
}
}
+QMarginsF QQuickPopupPrivate::windowInsets() const
+{
+ Q_Q(const QQuickPopup);
+ // If the popup has negative insets, it means that its background is pushed
+ // outside the bounds of the popup. This is fine when the popup is an item in the
+ // scene (Popup.Item), but will result in the background being clipped when using
+ // a window (Popup.Window). To avoid this, the window will been made bigger than
+ // the popup (according to the insets), to also include the part that ends up
+ // outside (which is usually a drop-shadow).
+ // Note that this also means that we need to take those extra margins into account
+ // whenever we resize or position the menu, so that the top-left of the popup ends
+ // up at the requested position, and not the top-left of the window.
+
+ if (!usePopupWindow() || (q->background() && q->background()->clip())) {
+ // Items in the scene are allowed to draw out-of-bounds, so we don't
+ // need to do anything if we're not using popup windows. The same is
+ // also true for popup windows if the background is clipped.
+ return {0, 0, 0, 0};
+ }
+
+ return {
+ q->leftInset() < 0 ? -q->leftInset() : 0,
+ q->rightInset() < 0 ? -q->rightInset() : 0,
+ q->topInset() < 0 ? -q->topInset() : 0,
+ q->bottomInset() < 0 ? -q->bottomInset() : 0
+ };
+}
+
+QPointF QQuickPopupPrivate::windowInsetsTopLeft() const
+{
+ const QMarginsF windowMargins = windowInsets();
+ return {windowMargins.left(), windowMargins.top()};
+}
+
+void QQuickPopupPrivate::setEffectivePosFromWindowPos(const QPointF &windowPos)
+{
+ // Popup operates internally with three different positions; requested
+ // position, effective position, and window position. The first is the
+ // position requested by the application, and the second is where the popup
+ // is actually placed. The reason for placing it on a different position than
+ // the one requested, is to keep it inside the window (in case of Popup.Item),
+ // or the screen (in case of Popup.Window).
+ // Additionally, since a popup can set Qt::FramelessWindowHint and draw the
+ // window frame from the background delegate, the effective position in that
+ // case is adjusted to be the top-left corner of the background delegate, rather
+ // than the top-left corner of the window. This allowes the background delegate
+ // to render a drop-shadow between the edge of the window and the background frame.
+ // Finally, the window position is the actual position of the window, including
+ // any drop-shadow effects. This posision can be calculated by taking
+ // the effective position and subtract the dropShadowOffset().
+ Q_Q(QQuickPopup);
+ const QPointF oldEffectivePos = effectivePos;
+ effectivePos = windowPos + windowInsetsTopLeft();
+ if (!qFuzzyCompare(oldEffectivePos.x(), effectivePos.x()))
+ emit q->xChanged();
+ if (!qFuzzyCompare(oldEffectivePos.y(), effectivePos.y()))
+ emit q->yChanged();
+}
+
#if QT_CONFIG(quicktemplates2_multitouch)
bool QQuickPopupPrivate::handleTouchEvent(QQuickItem *item, QTouchEvent *event)
{
@@ -578,37 +707,17 @@ bool QQuickPopupPrivate::prepareEnterTransition()
return false;
if (transitionState != EnterTransition) {
- QQuickOverlay *overlay = QQuickOverlay::overlay(window);
- const auto popupStack = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups();
- popupItem->setParentItem(overlay);
- // if there is a stack of popups, and the current top popup item belongs to an
- // ancestor of this popup, then make sure that this popup's item is at the top
- // of the stack.
- const QQuickPopup *topPopup = popupStack.isEmpty() ? nullptr : popupStack.first();
- const QObject *ancestor = q;
- while (ancestor && topPopup) {
- if (ancestor == topPopup)
- break;
- ancestor = ancestor->parent();
- }
- if (topPopup && topPopup != q && ancestor) {
- QQuickItem *topPopupItem = popupStack.first()->popupItem();
- popupItem->stackAfter(topPopupItem);
- // If the popup doesn't have an explicit z value set, set it to be at least as
- // high as the current top popup item so that later opened popups are on top.
- if (!hasZ)
- popupItem->setZ(qMax(topPopupItem->z(), popupItem->z()));
- }
+ visible = true;
+ adjustPopupItemParentAndWindow();
if (dim)
createOverlay();
showDimmer();
emit q->aboutToShow();
- visible = true;
transitionState = EnterTransition;
- popupItem->setVisible(true);
getPositioner()->setParentItem(parentItem);
emit q->visibleChanged();
+ QQuickOverlay *overlay = QQuickOverlay::overlay(window);
auto *overlayPrivate = QQuickOverlayPrivate::get(overlay);
if (overlayPrivate->lastActiveFocusItem.isNull())
overlayPrivate->lastActiveFocusItem = window->activeFocusItem();
@@ -654,7 +763,7 @@ void QQuickPopupPrivate::finalizeEnterTransition()
{
Q_Q(QQuickPopup);
transitionState = NoTransition;
- getPositioner()->reposition();
+ reposition();
emit q->openedChanged();
opened();
}
@@ -663,7 +772,7 @@ void QQuickPopupPrivate::finalizeExitTransition()
{
Q_Q(QQuickPopup);
getPositioner()->setParentItem(nullptr);
- if (popupItem) {
+ if (popupItem && !popupWindow) {
popupItem->setParentItem(nullptr);
popupItem->setVisible(false);
}
@@ -698,8 +807,8 @@ void QQuickPopupPrivate::finalizeExitTransition()
overlayPrivate->lastActiveFocusItem = nullptr;
}
}
-
visible = false;
+ adjustPopupItemParentAndWindow();
transitionState = NoTransition;
hadActiveFocusBeforeExitTransition = false;
emit q->visibleChanged();
@@ -716,6 +825,11 @@ void QQuickPopupPrivate::opened()
emit q->opened();
}
+Qt::WindowFlags QQuickPopupPrivate::popupWindowType() const
+{
+ return Qt::Popup | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint;
+}
+
QMarginsF QQuickPopupPrivate::getMargins() const
{
Q_Q(const QQuickPopup);
@@ -871,6 +985,86 @@ QPalette QQuickPopupPrivate::defaultPalette() const
return QQuickTheme::palette(QQuickTheme::System);
}
+QQuickPopup::PopupType QQuickPopupPrivate::resolvedPopupType() const
+{
+ // Whether or not the resolved popup type ends up the same as the preferred popup type
+ // depends on platform capabilities, the popup subclass, and sometimes also the location
+ // of the popup in the parent hierarchy (menus). This function can therefore be overridden
+ // to return the actual popup type that should be used, based on the knowledge the popup
+ // has just before it's about to be shown.
+
+ // PopupType::Native is not directly supported by QQuickPopup (only by subclasses).
+ // So for that case, we fall back to use PopupType::Window, if supported.
+ if (m_popupType == QQuickPopup::PopupType::Window
+ || m_popupType == QQuickPopup::PopupType::Native) {
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::Capability::MultipleWindows))
+ return QQuickPopup::PopupType::Window;
+ }
+
+ return QQuickPopup::PopupType::Item;
+}
+
+bool QQuickPopupPrivate::usePopupWindow() const
+{
+ return resolvedPopupType() == QQuickPopup::PopupType::Window;
+}
+
+void QQuickPopupPrivate::adjustPopupItemParentAndWindow()
+{
+ Q_Q(QQuickPopup);
+ QQuickOverlay *overlay = QQuickOverlay::overlay(window);
+
+ if (visible && popupWindowDirty) {
+ popupItem->setParentItem(overlay);
+ if (popupWindow) {
+ popupWindow->deleteLater();
+ popupWindow = nullptr;
+ }
+ popupWindowDirty = false;
+ }
+
+ if (usePopupWindow()) {
+ if (!popupWindow) {
+ popupWindow = new QQuickPopupWindow(q, window);
+ popupWindow->setWidth(popupItem->width() + windowInsets().left() + windowInsets().right());
+ popupWindow->setHeight(popupItem->height() + windowInsets().top() + windowInsets().bottom());
+ popupWindow->setModality(modal ? Qt::ApplicationModal : Qt::NonModal);
+ popupItem->resetTitle();
+ popupWindow->setTitle(m_title);
+ popupItem->setParentItem(popupWindow->contentItem());
+ popupItem->forceActiveFocus(Qt::PopupFocusReason);
+ }
+ popupItem->setVisible(true);
+ popupWindow->setVisible(visible);
+ } else {
+ if (visible) {
+ popupItem->setParentItem(overlay);
+ const auto popupStack = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups();
+ // if there is a stack of popups, and the current top popup item belongs to an
+ // ancestor of this popup, then make sure that this popup's item is at the top
+ // of the stack.
+ const QQuickPopup *topPopup = popupStack.isEmpty() ? nullptr : popupStack.first();
+ const QObject *ancestor = q;
+ while (ancestor && topPopup) {
+ if (ancestor == topPopup)
+ break;
+ ancestor = ancestor->parent();
+ }
+ if (topPopup && topPopup != q && ancestor) {
+ QQuickItem *topPopupItem = popupStack.first()->popupItem();
+ popupItem->stackAfter(topPopupItem);
+ // If the popup doesn't have an explicit z value set, set it to be at least as
+ // high as the current top popup item so that later opened popups are on top.
+ if (!hasZ)
+ popupItem->setZ(qMax(topPopupItem->z(), popupItem->z()));
+ }
+ }
+
+ popupItem->setTitle(m_title);
+ popupItem->setVisible(visible);
+ }
+}
+
static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQuickItem *parent)
{
QQuickItem *item = nullptr;
@@ -1113,8 +1307,7 @@ void QQuickPopup::close()
*/
qreal QQuickPopup::x() const
{
- Q_D(const QQuickPopup);
- return d->effectiveX;
+ return d_func()->effectivePos.x();
}
void QQuickPopup::setX(qreal x)
@@ -1132,8 +1325,7 @@ void QQuickPopup::setX(qreal x)
*/
qreal QQuickPopup::y() const
{
- Q_D(const QQuickPopup);
- return d->effectiveY;
+ return d_func()->effectivePos.y();
}
void QQuickPopup::setY(qreal y)
@@ -1144,8 +1336,7 @@ void QQuickPopup::setY(qreal y)
QPointF QQuickPopup::position() const
{
- Q_D(const QQuickPopup);
- return QPointF(d->effectiveX, d->effectiveY);
+ return d_func()->effectivePos;
}
void QQuickPopup::setPosition(const QPointF &pos)
@@ -1181,6 +1372,9 @@ void QQuickPopup::setPosition(const QPointF &pos)
of an already open popup, then it will be stacked on top of its parent.
This ensures that children are never hidden under their parents.
+ If the popup has its own window, the z-value will determine the window
+ stacking order instead.
+
The default z-value is \c 0.
\sa x, y
@@ -1195,9 +1389,13 @@ void QQuickPopup::setZ(qreal z)
{
Q_D(QQuickPopup);
d->hasZ = true;
- if (qFuzzyCompare(z, d->popupItem->z()))
+ bool previousZ = d->popupWindow ? d->popupWindow->z() : d->popupItem->z();
+ if (qFuzzyCompare(z, previousZ))
return;
- d->popupItem->setZ(z);
+ if (d->popupWindow)
+ d->popupWindow->setZ(z);
+ else
+ d->popupItem->setZ(z);
emit zChanged();
}
@@ -1223,7 +1421,16 @@ void QQuickPopup::setWidth(qreal width)
{
Q_D(QQuickPopup);
d->hasWidth = true;
- d->popupItem->setWidth(width);
+
+ // QQuickPopupWindow::setWidth() triggers a window resize event.
+ // This will cause QQuickPopupWindow::resizeEvent() to resize
+ // the popupItem. QQuickPopupItem::geometryChanged() calls QQuickPopup::geometryChange(),
+ // which emits widthChanged().
+
+ if (d->popupWindow)
+ d->popupWindow->setWidth(width + d->windowInsets().left() + d->windowInsets().right());
+ else
+ d->popupItem->setWidth(width);
}
void QQuickPopup::resetWidth()
@@ -1253,7 +1460,16 @@ void QQuickPopup::setHeight(qreal height)
{
Q_D(QQuickPopup);
d->hasHeight = true;
- d->popupItem->setHeight(height);
+
+ // QQuickPopupWindow::setHeight() triggers a window resize event.
+ // This will cause QQuickPopupWindow::resizeEvent() to resize
+ // the popupItem. QQuickPopupItem::geometryChanged() calls QQuickPopup::geometryChange(),
+ // which emits heightChanged().
+
+ if (d->popupWindow)
+ d->popupWindow->setHeight(height + d->windowInsets().top() + d->windowInsets().bottom());
+ else
+ d->popupItem->setHeight(height);
}
void QQuickPopup::resetHeight()
@@ -1862,7 +2078,7 @@ void QQuickPopup::resetParentItem()
if (QQuickWindow *window = qobject_cast<QQuickWindow *>(parent()))
setParentItem(window->contentItem());
else
- setParentItem(qobject_cast<QQuickItem *>(parent()));
+ setParentItem(findParentItem());
}
/*!
@@ -1993,17 +2209,18 @@ QQmlListProperty<QQuickItem> QQuickPopupPrivate::contentChildren()
\qmlproperty bool QtQuick.Controls::Popup::clip
This property holds whether clipping is enabled. The default value is \c false.
+ Clipping only works when the popup isn't in its own window.
*/
bool QQuickPopup::clip() const
{
Q_D(const QQuickPopup);
- return d->popupItem->clip();
+ return d->popupItem->clip() && !d->usePopupWindow();
}
void QQuickPopup::setClip(bool clip)
{
Q_D(QQuickPopup);
- if (clip == d->popupItem->clip())
+ if (clip == d->popupItem->clip() || d->usePopupWindow())
return;
d->popupItem->setClip(clip);
emit clipChanged();
@@ -2083,6 +2300,7 @@ void QQuickPopup::setModal(bool modal)
if (d->modal == modal)
return;
d->modal = modal;
+ d->popupWindowDirty = true;
if (d->complete && d->visible)
d->toggleOverlay();
emit modalChanged();
@@ -2613,6 +2831,57 @@ void QQuickPopup::resetBottomInset()
d->popupItem->resetBottomInset();
}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::Popup::popupType
+ \since 6.8
+
+ This property determines the type of popup that is preferred.
+
+ Available options:
+ \value Item The popup will be embedded into the \l{Popup Items}{same scene as the parent}, without the use of a separate window.
+ \value Window The popup will be presented in a \l {Popup Windows}{separate window}. If the platform doesn't support multiple windows,
+ \c Popup.Item will be used instead.
+ \value Native The popup will be native to the platform. If the platform doesn't support native popups,
+ \c Popup.Window will be used instead.
+
+ Whether a popup will be able to use the preferred type depends on the platform.
+ \c Popup.Item is supported on all platforms, but \c Popup.Window and \c Popup.Native
+ are normally only supported on desktop platforms. Additionally, if a popup is a
+ \l Menu inside a \l {Native menu bars}{native menubar}, the menu will be native as
+ well. And if the menu is a sub-menu inside another menu, the parent (or root) menu
+ will decide the type.
+
+ \note The default value is platform dependent, and can change in future versions of Qt.
+ Therefore, if you want to make sure that for example \c Popup.Item is always used on all
+ platforms, you should set it explicitly.
+
+ You can set this property to \c undefined, to restore its value back to its default type.
+
+ \sa {Popup type}
+*/
+QQuickPopup::PopupType QQuickPopup::popupType() const
+{
+ Q_D(const QQuickPopup);
+ return d->m_popupType;
+}
+
+void QQuickPopup::setPopupType(PopupType popupType)
+{
+ Q_D(QQuickPopup);
+ if (d->m_popupType == popupType)
+ return;
+
+ d->m_popupType = popupType;
+
+ emit popupTypeChanged();
+}
+
+void QQuickPopup::resetPopupType()
+{
+ setPopupType(PopupType::Item);
+}
+
/*!
\since QtQuick.Controls 2.3 (Qt 5.10)
\qmlproperty palette QtQuick.Controls::Popup::palette
@@ -2683,7 +2952,7 @@ void QQuickPopup::classBegin()
void QQuickPopup::componentComplete()
{
Q_D(QQuickPopup);
- qCDebug(lcPopup) << "componentComplete" << this;
+ qCDebug(lcQuickPopup) << "componentComplete" << this;
if (!parentItem())
resetParentItem();
@@ -2843,7 +3112,7 @@ void QQuickPopup::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
void QQuickPopup::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
{
- qCDebug(lcPopup) << "contentSizeChange called on" << this << "with newSize" << newSize << "oldSize" << oldSize;
+ qCDebug(lcQuickPopup) << "contentSizeChange called on" << this << "with newSize" << newSize << "oldSize" << oldSize;
if (!qFuzzyCompare(newSize.width(), oldSize.width()))
emit contentWidthChanged();
if (!qFuzzyCompare(newSize.height(), oldSize.height()))
@@ -2860,7 +3129,7 @@ void QQuickPopup::fontChange(const QFont &newFont, const QFont &oldFont)
void QQuickPopup::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
{
Q_D(QQuickPopup);
- qCDebug(lcPopup) << "geometryChange called on" << this << "with newGeometry" << newGeometry << "oldGeometry" << oldGeometry;
+ qCDebug(lcQuickPopup) << "geometryChange called on" << this << "with newGeometry" << newGeometry << "oldGeometry" << oldGeometry;
d->reposition();
if (!qFuzzyCompare(newGeometry.width(), oldGeometry.width())) {
emit widthChanged();
diff --git a/src/quicktemplates/qquickpopup_p.h b/src/quicktemplates/qquickpopup_p.h
index 9ffd94e70a..1f388d8adb 100644
--- a/src/quicktemplates/qquickpopup_p.h
+++ b/src/quicktemplates/qquickpopup_p.h
@@ -101,6 +101,7 @@ class Q_QUICKTEMPLATES2_EXPORT QQuickPopup : public QObject, public QQmlParserSt
Q_PROPERTY(qreal leftInset READ leftInset WRITE setLeftInset RESET resetLeftInset NOTIFY leftInsetChanged FINAL REVISION(2, 5))
Q_PROPERTY(qreal rightInset READ rightInset WRITE setRightInset RESET resetRightInset NOTIFY rightInsetChanged FINAL REVISION(2, 5))
Q_PROPERTY(qreal bottomInset READ bottomInset WRITE setBottomInset RESET resetBottomInset NOTIFY bottomInsetChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(PopupType popupType READ popupType WRITE setPopupType RESET resetPopupType NOTIFY popupTypeChanged FINAL REVISION(6, 8))
Q_CLASSINFO("DeferredPropertyNames", "background,contentItem")
Q_CLASSINFO("DefaultProperty", "contentData")
QML_NAMED_ELEMENT(Popup)
@@ -222,11 +223,11 @@ public:
void setDim(bool dim);
void resetDim();
- bool isVisible() const;
+ virtual bool isVisible() const;
virtual void setVisible(bool visible);
qreal opacity() const;
- void setOpacity(qreal opacity);
+ virtual void setOpacity(qreal opacity);
qreal scale() const;
void setScale(qreal scale);
@@ -311,6 +312,17 @@ public:
void setBottomInset(qreal inset);
void resetBottomInset();
+ enum PopupType {
+ Item,
+ Window,
+ Native
+ };
+ Q_ENUM(PopupType)
+
+ PopupType popupType() const;
+ void setPopupType(PopupType);
+ void resetPopupType();
+
public Q_SLOTS:
void open();
void close();
@@ -378,6 +390,7 @@ Q_SIGNALS:
Q_REVISION(2, 5) void leftInsetChanged();
Q_REVISION(2, 5) void rightInsetChanged();
Q_REVISION(2, 5) void bottomInsetChanged();
+ Q_REVISION(6, 8) void popupTypeChanged();
protected:
QQuickPopup(QQuickPopupPrivate &dd, QObject *parent);
@@ -433,8 +446,11 @@ protected:
bool setAccessibleProperty(const char *propertyName, const QVariant &value);
private:
+ QQuickItem *findParentItem() const;
+
Q_DISABLE_COPY(QQuickPopup)
Q_DECLARE_PRIVATE(QQuickPopup)
+ friend class QQuickPopupWindow;
friend class QQuickPopupItem;
friend class QQuickOverlay;
friend class QQuickOverlayPrivate;
diff --git a/src/quicktemplates/qquickpopup_p_p.h b/src/quicktemplates/qquickpopup_p_p.h
index 5572dd87d1..8d9c54ac9b 100644
--- a/src/quicktemplates/qquickpopup_p_p.h
+++ b/src/quicktemplates/qquickpopup_p_p.h
@@ -34,6 +34,7 @@ class QQuickTransitionManager;
class QQuickPopup;
class QQuickPopupAnchors;
class QQuickPopupItem;
+class QQuickPopupWindow;
class QQuickPopupPrivate;
class QQuickPopupPositioner;
@@ -84,6 +85,7 @@ public:
virtual bool handlePress(QQuickItem* item, const QPointF &point, ulong timestamp);
virtual bool handleMove(QQuickItem* item, const QPointF &point, ulong timestamp);
virtual bool handleRelease(QQuickItem* item, const QPointF &point, ulong timestamp);
+ virtual bool handleReleaseWithoutGrab(const QEventPoint &) { return false; }
virtual void handleUngrab();
bool handleMouseEvent(QQuickItem *item, QMouseEvent *event);
@@ -92,12 +94,20 @@ public:
bool handleTouchEvent(QQuickItem *item, QTouchEvent *event);
#endif
+ QMarginsF windowInsets() const;
+ QPointF windowInsetsTopLeft() const;
+ void setEffectivePosFromWindowPos(const QPointF &windowPos);
void reposition();
+ bool usePopupWindow() const;
+ void adjustPopupItemParentAndWindow();
void createOverlay();
void destroyDimmer();
void toggleOverlay();
void updateContentPalettes(const QPalette& parentPalette);
+
+ virtual QQuickPopup::PopupType resolvedPopupType() const;
+
virtual void showDimmer();
virtual void hideDimmer();
virtual void resizeDimmer();
@@ -109,6 +119,8 @@ public:
virtual void opened();
+ virtual Qt::WindowFlags popupWindowType() const;
+
QMarginsF getMargins() const;
void setTopMargin(qreal value, bool reset = false);
@@ -157,11 +169,11 @@ public:
bool outsideParentPressed = false;
bool inDestructor = false;
bool relaxEdgeConstraint = false;
+ bool popupWindowDirty = false;
int touchId = -1;
qreal x = 0;
qreal y = 0;
- qreal effectiveX = 0;
- qreal effectiveY = 0;
+ QPointF effectivePos;
qreal margins = -1;
qreal topMargin = 0;
qreal leftMargin = 0;
@@ -176,6 +188,7 @@ public:
QQuickTransition *enter = nullptr;
QQuickTransition *exit = nullptr;
QQuickPopupItem *popupItem = nullptr;
+ QQuickPopupWindow *popupWindow = nullptr;
QQuickPopupPositioner *positioner = nullptr;
QList<QQuickStateAction> enterActions;
QList<QQuickStateAction> exitActions;
@@ -184,6 +197,8 @@ public:
qreal explicitDimmerOpacity = 0;
qreal prevOpacity = 0;
qreal prevScale = 0;
+ QString m_title;
+ QQuickPopup::PopupType m_popupType = QQuickPopup::Item;
friend class QQuickPopupTransitionManager;
};
diff --git a/src/quicktemplates/qquickpopupitem.cpp b/src/quicktemplates/qquickpopupitem.cpp
index 574ea4589a..514ddc8eb2 100644
--- a/src/quicktemplates/qquickpopupitem.cpp
+++ b/src/quicktemplates/qquickpopupitem.cpp
@@ -14,7 +14,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcPopupItem, "qt.quick.controls.popupitem")
+Q_STATIC_LOGGING_CATEGORY(lcPopupItem, "qt.quick.controls.popupitem")
QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup)
: popup(popup)
diff --git a/src/quicktemplates/qquickpopuppositioner.cpp b/src/quicktemplates/qquickpopuppositioner.cpp
index f8113a5526..08b6e9d358 100644
--- a/src/quicktemplates/qquickpopuppositioner.cpp
+++ b/src/quicktemplates/qquickpopuppositioner.cpp
@@ -5,6 +5,7 @@
#include "qquickpopuppositioner_p_p.h"
#include "qquickpopupanchors_p.h"
#include "qquickpopupitem_p_p.h"
+#include "qquickpopupwindow_p_p.h"
#include "qquickpopup_p_p.h"
#include <QtCore/qloggingcategory.h>
@@ -13,7 +14,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcPopupPositioner, "qt.quick.controls.popuppositioner")
+Q_STATIC_LOGGING_CATEGORY(lcPopupPositioner, "qt.quick.controls.popuppositioner")
static const QQuickItemPrivate::ChangeTypes AncestorChangeTypes = QQuickItemPrivate::Geometry
| QQuickItemPrivate::Parent
@@ -72,7 +73,40 @@ void QQuickPopupPositioner::setParentItem(QQuickItem *parent)
void QQuickPopupPositioner::reposition()
{
- QQuickItem *popupItem = m_popup->popupItem();
+ auto p = QQuickPopupPrivate::get(popup());
+ QQuickPopupItem *popupItem = static_cast<QQuickPopupItem *>(m_popup->popupItem());
+
+ if (p->usePopupWindow()) {
+ QPointF requestedPos(p->x, p->y);
+ // Shift the window position a bit back, so that the top-left of the
+ // background frame ends up at the requested position.
+ QPointF windowPos = requestedPos - p->windowInsetsTopLeft();
+
+ if (!p->popupWindow || !p->parentItem) {
+ // If we don't have a popupWindow, set a temporary effective pos. Otherwise
+ // wait for a callback to QQuickPopupWindow::handlePopupPositionChangeFromWindowSystem()
+ // from setting p->popupWindow->setPosition() below.
+ p->setEffectivePosFromWindowPos(windowPos);
+ return;
+ }
+
+ const QQuickItem *centerInParent = p->anchors ? p->getAnchors()->centerIn() : nullptr;
+ const QQuickOverlay *centerInOverlay = qobject_cast<const QQuickOverlay *>(centerInParent);
+
+ if (centerInParent == p->parentItem || centerInOverlay) {
+ windowPos = centerInOverlay ? QPoint(qRound(centerInOverlay->width() / 2.0), qRound(centerInOverlay->height() / 2.0))
+ : QPoint(qRound(p->parentItem->width() / 2.0), qRound(p->parentItem->height() / 2.0));
+ windowPos -= QPoint(qRound(p->popupItem->width() / 2.0), qRound(p->popupItem->height() / 2.0));
+
+ } else if (centerInParent)
+ qmlWarning(popup()) << "Popup can only be centered within its immediate parent or Overlay.overlay";
+
+ const QPointF globalCoords = p->parentItem->mapToGlobal(windowPos.x(), windowPos.y());
+ p->popupWindow->setPosition(globalCoords.x(), globalCoords.y());
+ p->popupItem->setPosition(p->windowInsetsTopLeft());
+ return;
+ }
+
if (!popupItem->isVisible())
return;
@@ -90,14 +124,12 @@ void QQuickPopupPositioner::reposition()
bool widthAdjusted = false;
bool heightAdjusted = false;
- QQuickPopupPrivate *p = QQuickPopupPrivate::get(m_popup);
const QQuickItem *centerInParent = p->anchors ? p->getAnchors()->centerIn() : nullptr;
const QQuickOverlay *centerInOverlay = qobject_cast<const QQuickOverlay*>(centerInParent);
QRectF rect(!centerInParent ? p->allowHorizontalMove ? p->x : popupItem->x() : 0,
!centerInParent ? p->allowVerticalMove ? p->y : popupItem->y() : 0,
- !p->hasWidth && iw > 0 ? iw : w,
- !p->hasHeight && ih > 0 ? ih : h);
+ !p->hasWidth && iw > 0 ? iw : w, !p->hasHeight && ih > 0 ? ih : h);
bool relaxEdgeConstraint = p->relaxEdgeConstraint;
if (m_parentItem) {
// m_parentItem is the parent that the popup should open in,
@@ -230,21 +262,18 @@ void QQuickPopupPositioner::reposition()
m_positioning = true;
- popupItem->setPosition(rect.topLeft());
+ const QPointF windowPos = rect.topLeft();
+ popupItem->setPosition(windowPos);
// If the popup was assigned a parent, rect will be in scene coordinates,
// so we need to map its top left back to item coordinates.
// However, if centering within the overlay, the coordinates will be relative
// to the window, so we don't need to do anything.
- const QPointF effectivePos = m_parentItem && !centerInOverlay ? m_parentItem->mapFromScene(rect.topLeft()) : rect.topLeft();
- if (!qFuzzyCompare(p->effectiveX, effectivePos.x())) {
- p->effectiveX = effectivePos.x();
- emit m_popup->xChanged();
- }
- if (!qFuzzyCompare(p->effectiveY, effectivePos.y())) {
- p->effectiveY = effectivePos.y();
- emit m_popup->yChanged();
- }
+ // The same applies to popups that are in their own dedicated window.
+ if (m_parentItem && !centerInOverlay)
+ p->setEffectivePosFromWindowPos(m_parentItem->mapFromScene(windowPos));
+ else
+ p->setEffectivePosFromWindowPos(windowPos);
if (!p->hasWidth && widthAdjusted && rect.width() > 0) {
popupItem->setWidth(rect.width() / m_popupScale);
diff --git a/src/quicktemplates/qquickpopupwindow.cpp b/src/quicktemplates/qquickpopupwindow.cpp
new file mode 100644
index 0000000000..ba00cbb11e
--- /dev/null
+++ b/src/quicktemplates/qquickpopupwindow.cpp
@@ -0,0 +1,265 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qquickpopupwindow_p_p.h"
+#include "qquickcombobox_p.h"
+#include "qquickpopup_p.h"
+#include "qquickpopup_p_p.h"
+#include "qquickmenu_p_p.h"
+#include "qquickmenubar_p_p.h"
+#include "qquickpopupitem_p_p.h"
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/private/qeventpoint_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickwindowmodule_p.h>
+#include <QtQuick/private/qquickwindowmodule_p_p.h>
+#include <qpa/qplatformwindow_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_STATIC_LOGGING_CATEGORY(lcPopupWindow, "qt.quick.controls.popup.window")
+
+class QQuickPopupWindowPrivate : public QQuickWindowQmlImplPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPopupWindow)
+
+public:
+ QPointer<QQuickItem> m_popupItem;
+ QPointer<QQuickPopup> m_popup;
+
+ void forwardEventToParentMenuOrMenuBar(QEvent *event);
+};
+
+QQuickPopupWindow::QQuickPopupWindow(QQuickPopup *popup, QWindow *parent)
+ : QQuickWindowQmlImpl(*(new QQuickPopupWindowPrivate), nullptr)
+{
+ Q_D(QQuickPopupWindow);
+
+ d->m_popup = popup;
+ d->m_popupItem = popup->popupItem();
+ setTransientParent(parent);
+
+ connect(d->m_popup, &QQuickPopup::windowChanged, this, &QQuickPopupWindow::windowChanged);
+ connect(d->m_popup, &QQuickPopup::implicitWidthChanged, this, &QQuickPopupWindow::implicitWidthChanged);
+ connect(d->m_popup, &QQuickPopup::implicitHeightChanged, this, &QQuickPopupWindow::implicitHeightChanged);
+ connect(d->m_popup->window(), &QWindow::xChanged, this, &QQuickPopupWindow::parentWindowXChanged);
+ connect(d->m_popup->window(), &QWindow::yChanged, this, &QQuickPopupWindow::parentWindowYChanged);
+
+ setWidth(d->m_popupItem->implicitWidth());
+ setHeight(d->m_popupItem->implicitHeight());
+
+ const auto flags = QQuickPopupPrivate::get(popup)->popupWindowType();
+
+ // For popup windows, we'll need to draw everything, in order to have enough control over the styling.
+ if (flags & Qt::Popup)
+ setColor(QColorConstants::Transparent);
+
+ setFlags(flags);
+
+ qCDebug(lcPopupWindow) << "Created popup window with flags: " << flags;
+}
+
+QQuickPopupWindow::~QQuickPopupWindow()
+{
+ Q_D(QQuickPopupWindow);
+ disconnect(d->m_popup, &QQuickPopup::windowChanged, this, &QQuickPopupWindow::windowChanged);
+ disconnect(d->m_popup, &QQuickPopup::implicitWidthChanged, this, &QQuickPopupWindow::implicitWidthChanged);
+ disconnect(d->m_popup, &QQuickPopup::implicitHeightChanged, this, &QQuickPopupWindow::implicitHeightChanged);
+ disconnect(d->m_popup->window(), &QWindow::xChanged, this, &QQuickPopupWindow::parentWindowXChanged);
+ disconnect(d->m_popup->window(), &QWindow::yChanged, this, &QQuickPopupWindow::parentWindowYChanged);
+}
+
+QQuickPopup *QQuickPopupWindow::popup() const
+{
+ Q_D(const QQuickPopupWindow);
+ return d->m_popup;
+}
+
+void QQuickPopupWindow::hideEvent(QHideEvent *e)
+{
+ Q_D(QQuickPopupWindow);
+ QQuickWindow::hideEvent(e);
+ if (QQuickPopup *popup = d->m_popup)
+ popup->setVisible(false);
+}
+
+void QQuickPopupWindow::moveEvent(QMoveEvent *e)
+{
+ handlePopupPositionChangeFromWindowSystem(e->pos());
+}
+
+void QQuickPopupWindow::resizeEvent(QResizeEvent *e)
+{
+ Q_D(QQuickPopupWindow);
+ QQuickWindowQmlImpl::resizeEvent(e);
+
+ if (!d->m_popupItem)
+ return;
+
+ qCDebug(lcPopupWindow) << "A window system event changed the popup's size to be " << e->size();
+ const QMarginsF windowInsets = QQuickPopupPrivate::get(d->m_popup)->windowInsets();
+ d->m_popupItem->setWidth(e->size().width() - windowInsets.left() - windowInsets.right());
+ d->m_popupItem->setHeight(e->size().height() - windowInsets.top() - windowInsets.bottom());
+}
+
+/*! \internal
+ We want to handle menus specially, compared to other popups. For menus, we
+ want all open parent menus and sub menus that belong together to almost
+ act as a single popup WRT hover event delivery. This will allow the user to
+ hover and highlight MenuItems inside all of them, not just the leaf menu.
+ This function will therefore find the menu, or menu bar, under the event's
+ position, and forward the event to it. But note that this forwarding will
+ happen in parallel with normal event delivery (we don't eat the events), as
+ we don't want to break the delivery to e.g grabbers.
+ */
+void QQuickPopupWindowPrivate::forwardEventToParentMenuOrMenuBar(QEvent *event)
+{
+ Q_Q(QQuickPopupWindow);
+
+ if (!event->isPointerEvent())
+ return;
+ auto menu = qobject_cast<QQuickMenu *>(q->popup());
+ if (!menu)
+ return;
+
+ auto *pe = static_cast<QPointerEvent *>(event);
+ const QPointF globalPos = pe->points().first().globalPosition();
+
+ // If there is a Menu or a MenuBar under the mouse, resolve its window.
+ QQuickPopupWindow *targetPopupWindow = nullptr;
+ QQuickWindow *targetWindow = nullptr;
+
+ QObject *menuParent = menu;
+ while (menuParent) {
+ if (auto parentMenu = qobject_cast<QQuickMenu *>(menuParent)) {
+ QQuickPopupWindow *popupWindow = QQuickMenuPrivate::get(parentMenu)->popupWindow;
+ auto popup_d = QQuickPopupPrivate::get(popupWindow->popup());
+ QPointF scenePos = popupWindow->contentItem()->mapFromGlobal(globalPos);
+ if (popup_d->contains(scenePos)) {
+ targetPopupWindow = popupWindow;
+ targetWindow = popupWindow;
+ break;
+ }
+ } else if (auto menuBar = qobject_cast<QQuickMenuBar *>(menuParent)) {
+ const QPointF menuBarPos = menuBar->mapFromGlobal(globalPos);
+ if (menuBar->contains(menuBarPos))
+ targetWindow = menuBar->window();
+ break;
+ }
+
+ menuParent = menuParent->parent();
+ }
+
+ if (!targetPopupWindow) {
+ if (pe->isBeginEvent()) {
+ // A QQuickPopupWindow can be bigger than the Popup itself, to make room
+ // for a drop-shadow. Close all popups if the user clicks either on the
+ // shadow or outside the window.
+ QGuiApplicationPrivate::closeAllPopups();
+ return;
+ }
+ }
+
+ if (!targetWindow)
+ return;
+
+ if (pe->isUpdateEvent()){
+ // Forward move events to the target window
+ const auto scenePos = pe->point(0).scenePosition();
+ const auto translatedScenePos = targetWindow->mapFromGlobal(globalPos);
+ QMutableEventPoint::setScenePosition(pe->point(0), translatedScenePos);
+ auto *grabber = pe->exclusiveGrabber(pe->point(0));
+
+ if (grabber) {
+ // Temporarily disable the grabber, to stop the delivery agent inside
+ // targetWindow from forwarding the event to an item outside the menu
+ // or menubar. This is especially important to support a press on e.g
+ // a MenuBarItem, followed by a drag-and-release on top of a MenuItem.
+ pe->setExclusiveGrabber(pe->point(0), nullptr);
+ }
+
+ qCDebug(lcPopupWindow) << "forwarding" << pe << "to popup menu:" << targetWindow;
+ QQuickWindowPrivate::get(targetWindow)->deliveryAgent->event(pe);
+
+ // Restore the event before we return
+ QMutableEventPoint::setScenePosition(pe->point(0), scenePos);
+ if (grabber)
+ pe->setExclusiveGrabber(pe->point(0), grabber);
+ } else if (pe->isEndEvent()) {
+ // To support opening a Menu on press (e.g on a MenuBarItem), followed by
+ // a drag and release on a MenuItem inside the Menu, we ask the Menu to
+ // perform a click on the active MenuItem, if any.
+ if (targetPopupWindow)
+ QQuickPopupPrivate::get(targetPopupWindow->popup())->handleReleaseWithoutGrab(pe->point(0));
+ }
+}
+
+bool QQuickPopupWindow::event(QEvent *e)
+{
+ Q_D(QQuickPopupWindow);
+ d->forwardEventToParentMenuOrMenuBar(e);
+
+ return QQuickWindowQmlImpl::event(e);
+}
+
+void QQuickPopupWindow::windowChanged(QWindow *window)
+{
+ if (window) {
+ connect(window, &QWindow::xChanged, this, &QQuickPopupWindow::parentWindowXChanged);
+ connect(window, &QWindow::yChanged, this, &QQuickPopupWindow::parentWindowYChanged);
+ }
+}
+
+QPoint QQuickPopupWindow::global2Local(const QPoint &pos) const
+{
+ Q_D(const QQuickPopupWindow);
+ QQuickPopup *popup = d->m_popup;
+ Q_ASSERT(popup);
+ const QPoint scenePos = popup->window()->mapFromGlobal(pos);
+ // Popup's coordinates are relative to the nearest parent item.
+ return popup->parentItem() ? popup->parentItem()->mapFromScene(scenePos).toPoint() : scenePos;
+}
+
+void QQuickPopupWindow::parentWindowXChanged(int newX)
+{
+ const auto popupLocalPos = global2Local({x(), y()});
+ handlePopupPositionChangeFromWindowSystem({newX + popupLocalPos.x(), y()});
+}
+
+void QQuickPopupWindow::parentWindowYChanged(int newY)
+{
+ const auto popupLocalPos = global2Local({x(), y()});
+ handlePopupPositionChangeFromWindowSystem({x(), newY + popupLocalPos.y()});
+}
+
+void QQuickPopupWindow::handlePopupPositionChangeFromWindowSystem(const QPoint &pos)
+{
+ Q_D(QQuickPopupWindow);
+ QQuickPopup *popup = d->m_popup;
+ if (!popup)
+ return;
+ QQuickPopupPrivate *popupPrivate = QQuickPopupPrivate::get(popup);
+
+ const auto windowPos = global2Local(pos);
+ qCDebug(lcPopupWindow) << "A window system event changed the popup's position to be " << windowPos;
+ popupPrivate->setEffectivePosFromWindowPos(windowPos);
+}
+
+void QQuickPopupWindow::implicitWidthChanged()
+{
+ Q_D(const QQuickPopupWindow);
+ if (auto popup = d->m_popup)
+ setWidth(popup->implicitWidth());
+}
+
+void QQuickPopupWindow::implicitHeightChanged()
+{
+ Q_D(const QQuickPopupWindow);
+ if (auto popup = d->m_popup)
+ setHeight(popup->implicitHeight());
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/quicktemplates/qquickpopupwindow_p_p.h b/src/quicktemplates/qquickpopupwindow_p_p.h
new file mode 100644
index 0000000000..0b9842c059
--- /dev/null
+++ b/src/quicktemplates/qquickpopupwindow_p_p.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQUICKPOPUPWINDOW_P_P_H
+#define QQUICKPOPUPWINDOW_P_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 <QtQuick/private/qquickwindowmodule_p.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPopup;
+class QQuickPopupWindowPrivate;
+
+class Q_QUICKTEMPLATES2_EXPORT QQuickPopupWindow : public QQuickWindowQmlImpl
+{
+ Q_OBJECT
+ QML_ANONYMOUS
+
+public:
+ explicit QQuickPopupWindow(QQuickPopup *popup, QWindow *parent = nullptr);
+ ~QQuickPopupWindow();
+ QQuickPopup *popup() const;
+
+protected:
+ void hideEvent(QHideEvent *e) override;
+ void moveEvent(QMoveEvent *e) override;
+ void resizeEvent(QResizeEvent *e) override;
+ bool event(QEvent *e) override;
+
+private:
+ void windowChanged(QWindow *window);
+ QPoint global2Local(const QPoint& pos) const;
+ void parentWindowXChanged(int newX);
+ void parentWindowYChanged(int newY);
+ void handlePopupPositionChangeFromWindowSystem(const QPoint &pos);
+ void implicitWidthChanged();
+ void implicitHeightChanged();
+
+ Q_DISABLE_COPY(QQuickPopupWindow)
+ Q_DECLARE_PRIVATE(QQuickPopupWindow)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPOPUPWINDOW_P_P_H
diff --git a/src/quicktemplates/qquickrangeslider.cpp b/src/quicktemplates/qquickrangeslider.cpp
index d97dfdff90..4715959758 100644
--- a/src/quicktemplates/qquickrangeslider.cpp
+++ b/src/quicktemplates/qquickrangeslider.cpp
@@ -712,7 +712,7 @@ void QQuickRangeSlider::setTo(qreal to)
This property holds the threshold (in logical pixels) at which a touch drag event will be initiated.
The mouse drag threshold won't be affected.
- The default value is \c Qt.styleHints.startDragDistance.
+ The default value is \c Application.styleHints.startDragDistance.
\sa QStyleHints
diff --git a/src/quicktemplates/qquickselectionrectangle.cpp b/src/quicktemplates/qquickselectionrectangle.cpp
index 435b12819b..5f8dff758e 100644
--- a/src/quicktemplates/qquickselectionrectangle.cpp
+++ b/src/quicktemplates/qquickselectionrectangle.cpp
@@ -170,7 +170,7 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
else
m_selectable->setSelectionEndPos(m_scrollToPoint);
updateHandles();
- const QSizeF dist = m_selectable->scrollTowardsSelectionPoint(m_scrollToPoint, m_scrollSpeed);
+ const QSizeF dist = m_selectable->scrollTowardsPoint(m_scrollToPoint, m_scrollSpeed);
m_scrollToPoint.rx() += dist.width() > 0 ? m_scrollSpeed.width() : -m_scrollSpeed.width();
m_scrollToPoint.ry() += dist.height() > 0 ? m_scrollSpeed.height() : -m_scrollSpeed.height();
m_scrollSpeed = QSizeF(qAbs(dist.width() * 0.007), qAbs(dist.height() * 0.007));
@@ -242,19 +242,9 @@ QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
m_selectable->setSelectionEndPos(pos);
updateHandles();
updateActiveState(true);
- } else if (modifiers == Qt::ControlModifier) {
- // Select a single cell, but keep the old selection (unless
- // m_selectable->startSelection(pos, modifiers) returns false, which
- // it will if selectionMode only allows a single selection).
- if (!m_selectable->startSelection(pos, modifiers))
- return;
- m_selectable->setSelectionStartPos(pos);
- m_selectable->setSelectionEndPos(pos);
- updateHandles();
- updateActiveState(true);
- } else if (modifiers == Qt::NoModifier) {
- // Select a single cell
- m_selectable->clearSelection();
+ } else {
+ // Select a single cell. m_selectable->startSelection() will decide
+ // if the existing selection should also be cleared.
if (!m_selectable->startSelection(pos, modifiers))
return;
m_selectable->setSelectionStartPos(pos);
@@ -310,7 +300,7 @@ void QQuickSelectionRectanglePrivate::scrollTowardsPos(const QPointF &pos)
if (m_scrollTimer.isActive())
return;
- const QSizeF dist = m_selectable->scrollTowardsSelectionPoint(m_scrollToPoint, m_scrollSpeed);
+ const QSizeF dist = m_selectable->scrollTowardsPoint(m_scrollToPoint, m_scrollSpeed);
if (!dist.isNull())
m_scrollTimer.start(1);
}
diff --git a/src/quicktemplates/qquickshortcutcontext.cpp b/src/quicktemplates/qquickshortcutcontext.cpp
index 503eb270a7..e3e5524100 100644
--- a/src/quicktemplates/qquickshortcutcontext.cpp
+++ b/src/quicktemplates/qquickshortcutcontext.cpp
@@ -17,7 +17,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcContextMatcher, "qt.quick.controls.shortcutcontext.matcher")
+Q_STATIC_LOGGING_CATEGORY(lcContextMatcher, "qt.quick.controls.shortcutcontext.matcher")
static bool isBlockedByPopup(QQuickItem *item)
{
diff --git a/src/quicktemplates/qquickslider.cpp b/src/quicktemplates/qquickslider.cpp
index 04b5589524..062efb3768 100644
--- a/src/quicktemplates/qquickslider.cpp
+++ b/src/quicktemplates/qquickslider.cpp
@@ -669,7 +669,7 @@ void QQuickSlider::decrease()
This property holds the threshold (in logical pixels) at which a touch drag event will be initiated.
The mouse drag threshold won't be affected.
- The default value is \c Qt.styleHints.startDragDistance.
+ The default value is \c Application.styleHints.startDragDistance.
\sa QStyleHints
*/
diff --git a/src/quicktemplates/qquickspinbox.cpp b/src/quicktemplates/qquickspinbox.cpp
index 2a68edac33..6c5d47b69d 100644
--- a/src/quicktemplates/qquickspinbox.cpp
+++ b/src/quicktemplates/qquickspinbox.cpp
@@ -2,19 +2,14 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquickspinbox_p.h"
-#include "qquickcontrol_p_p.h"
-#include "qquickindicatorbutton_p.h"
-#include "qquickdeferredexecute_p_p.h"
-#include <QtGui/qguiapplication.h>
-#include <QtGui/qstylehints.h>
+#include <private/qquickcontrol_p_p.h>
+#include <private/qquickindicatorbutton_p.h>
+#include <private/qquicktextinput_p.h>
+
+#include <private/qqmlengine_p.h>
#include <QtQml/qqmlinfo.h>
-#if QT_CONFIG(qml_locale)
-#include <QtQml/private/qqmllocale_p.h>
-#endif
-#include <QtQml/private/qqmlengine_p.h>
-#include <QtQuick/private/qquicktextinput_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/quicktemplates/qquicksplitview.cpp b/src/quicktemplates/qquicksplitview.cpp
index 1d41016f94..67d8845917 100644
--- a/src/quicktemplates/qquicksplitview.cpp
+++ b/src/quicktemplates/qquicksplitview.cpp
@@ -221,9 +221,9 @@ QT_BEGIN_NAMESPACE
\sa SplitHandle, {Customizing SplitView}, {Container Controls}
*/
-Q_LOGGING_CATEGORY(qlcQQuickSplitView, "qt.quick.controls.splitview")
-Q_LOGGING_CATEGORY(qlcQQuickSplitViewPointer, "qt.quick.controls.splitview.pointer")
-Q_LOGGING_CATEGORY(qlcQQuickSplitViewState, "qt.quick.controls.splitview.state")
+Q_STATIC_LOGGING_CATEGORY(qlcQQuickSplitView, "qt.quick.controls.splitview")
+Q_STATIC_LOGGING_CATEGORY(qlcQQuickSplitViewPointer, "qt.quick.controls.splitview.pointer")
+Q_STATIC_LOGGING_CATEGORY(qlcQQuickSplitViewState, "qt.quick.controls.splitview.state")
/*
Updates m_fillIndex to be between 0 .. (item count - 1).
diff --git a/src/quicktemplates/qquickswipedelegate.cpp b/src/quicktemplates/qquickswipedelegate.cpp
index 36782fee8c..dbf8db0f75 100644
--- a/src/quicktemplates/qquickswipedelegate.cpp
+++ b/src/quicktemplates/qquickswipedelegate.cpp
@@ -782,7 +782,9 @@ bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEv
if (item == q && !pressed)
return false;
- const qreal distance = (event->globalPosition() - event->points().first().globalPressPosition()).x();
+ const qreal distance = (event->globalPosition().x() != qInf() && event->globalPosition().y() != qInf()) ?
+ (item->mapFromGlobal(event->globalPosition()) -
+ item->mapFromGlobal(event->points().first().globalPressPosition())).x() : 0;
if (!q->keepMouseGrab()) {
// We used to use the custom threshold that QQuickDrawerPrivate::grabMouse used,
// but since it's larger than what Flickable uses, it results in Flickable
diff --git a/src/quicktemplates/qquicktextarea.cpp b/src/quicktemplates/qquicktextarea.cpp
index fb4702928e..a53f4ac542 100644
--- a/src/quicktemplates/qquicktextarea.cpp
+++ b/src/quicktemplates/qquicktextarea.cpp
@@ -472,6 +472,16 @@ QPalette QQuickTextAreaPrivate::defaultPalette() const
return QQuickTheme::palette(QQuickTheme::TextArea);
}
+bool QQuickTextAreaPrivate::setLastFocusChangeReason(Qt::FocusReason reason)
+{
+ Q_Q(QQuickTextArea);
+ const auto focusReasonChanged = QQuickItemPrivate::setLastFocusChangeReason(reason);
+ if (focusReasonChanged)
+ emit q->focusReasonChanged();
+
+ return focusReasonChanged;
+}
+
QQuickTextArea::QQuickTextArea(QQuickItem *parent)
: QQuickTextEdit(*(new QQuickTextAreaPrivate), parent)
{
@@ -663,7 +673,6 @@ void QQuickTextArea::setFocusReason(Qt::FocusReason reason)
{
Q_D(QQuickTextArea);
d->setLastFocusChangeReason(reason);
- emit focusReasonChanged();
}
diff --git a/src/quicktemplates/qquicktextarea_p_p.h b/src/quicktemplates/qquicktextarea_p_p.h
index 5e406d869e..849c22b97c 100644
--- a/src/quicktemplates/qquicktextarea_p_p.h
+++ b/src/quicktemplates/qquicktextarea_p_p.h
@@ -96,6 +96,8 @@ public:
QPalette defaultPalette() const override;
+ bool setLastFocusChangeReason(Qt::FocusReason reason) override;
+
#if QT_CONFIG(quicktemplates2_hover)
bool hovered = false;
bool explicitHoverEnabled = false;
diff --git a/src/quicktemplates/qquicktextfield.cpp b/src/quicktemplates/qquicktextfield.cpp
index 9513be3f3b..7163f2a302 100644
--- a/src/quicktemplates/qquicktextfield.cpp
+++ b/src/quicktemplates/qquicktextfield.cpp
@@ -364,6 +364,16 @@ QPalette QQuickTextFieldPrivate::defaultPalette() const
return QQuickTheme::palette(QQuickTheme::TextField);
}
+bool QQuickTextFieldPrivate::setLastFocusChangeReason(Qt::FocusReason reason)
+{
+ Q_Q(QQuickTextField);
+ const auto focusReasonChanged = QQuickItemPrivate::setLastFocusChangeReason(reason);
+ if (focusReasonChanged)
+ emit q->focusReasonChanged();
+
+ return focusReasonChanged;
+}
+
QQuickTextField::QQuickTextField(QQuickItem *parent)
: QQuickTextInput(*(new QQuickTextFieldPrivate), parent)
{
@@ -549,7 +559,6 @@ void QQuickTextField::setFocusReason(Qt::FocusReason reason)
{
Q_D(QQuickTextField);
d->setLastFocusChangeReason(reason);
- emit focusReasonChanged();
}
/*!
diff --git a/src/quicktemplates/qquicktextfield_p_p.h b/src/quicktemplates/qquicktextfield_p_p.h
index c8afee8ba3..ac75460b7e 100644
--- a/src/quicktemplates/qquicktextfield_p_p.h
+++ b/src/quicktemplates/qquicktextfield_p_p.h
@@ -94,6 +94,8 @@ public:
QPalette defaultPalette() const override;
+ bool setLastFocusChangeReason(Qt::FocusReason reason) override;
+
#if QT_CONFIG(quicktemplates2_hover)
bool hovered = false;
bool explicitHoverEnabled = false;
diff --git a/src/quicktemplates/qquicktooltip.cpp b/src/quicktemplates/qquicktooltip.cpp
index 2a78e4d344..0493cd5f4e 100644
--- a/src/quicktemplates/qquicktooltip.cpp
+++ b/src/quicktemplates/qquicktooltip.cpp
@@ -102,6 +102,8 @@ public:
void opened() override;
+ Qt::WindowFlags popupWindowType() const override;
+
QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::ToolTip); }
int delay = 0;
@@ -141,6 +143,11 @@ void QQuickToolTipPrivate::opened()
startTimeout();
}
+Qt::WindowFlags QQuickToolTipPrivate::popupWindowType() const
+{
+ return Qt::ToolTip;
+}
+
QQuickToolTip::QQuickToolTip(QQuickItem *parent)
: QQuickPopup(*(new QQuickToolTipPrivate), parent)
{
diff --git a/src/quicktemplates/qquicktumbler.cpp b/src/quicktemplates/qquicktumbler.cpp
index 71766cc698..aaa6fdb518 100644
--- a/src/quicktemplates/qquicktumbler.cpp
+++ b/src/quicktemplates/qquicktumbler.cpp
@@ -12,7 +12,7 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcTumbler, "qt.quick.controls.tumbler")
+Q_STATIC_LOGGING_CATEGORY(lcTumbler, "qt.quick.controls.tumbler")
/*!
\qmltype Tumbler
diff --git a/src/quicktestutils/quick/visualtestutils_p.h b/src/quicktestutils/quick/visualtestutils_p.h
index 48f8b2d8f9..9b1c9a2aeb 100644
--- a/src/quicktestutils/quick/visualtestutils_p.h
+++ b/src/quicktestutils/quick/visualtestutils_p.h
@@ -15,6 +15,8 @@
// We mean it.
//
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformintegration.h>
#include <QtQml/qqmlexpression.h>
#include <QtQuick/private/qquickitem_p.h>
@@ -226,6 +228,10 @@ namespace QQuickVisualTestUtils
#define QQUICK_VERIFY_POLISH(item) \
QTRY_COMPARE(QQuickItemPrivate::get(item)->polishScheduled, false)
+#define SKIP_IF_NO_WINDOW_ACTIVATION \
+if (!(QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))) \
+ QSKIP("Window activation is not supported on this platform");
+
QT_END_NAMESPACE
#endif // QQUICKVISUALTESTUTILS_P_H
diff --git a/src/quickvectorimage/CMakeLists.txt b/src/quickvectorimage/CMakeLists.txt
index ecca0432e5..b0921cdc63 100644
--- a/src/quickvectorimage/CMakeLists.txt
+++ b/src/quickvectorimage/CMakeLists.txt
@@ -20,7 +20,6 @@ qt_internal_add_module(QuickVectorImageGeneratorPrivate
Qt::QuickPrivate
Qt::QuickShapesPrivate
Qt::SvgPrivate
- GENERATE_CPP_EXPORTS
)
qt_internal_add_qml_module(QuickVectorImage
@@ -36,5 +35,4 @@ qt_internal_add_qml_module(QuickVectorImage
Qt::QuickPrivate
Qt::QuickVectorImageGeneratorPrivate
Qt::SvgPrivate
- GENERATE_CPP_EXPORTS
)
diff --git a/src/quickvectorimage/generator/qquickgenerator.cpp b/src/quickvectorimage/generator/qquickgenerator.cpp
index 505b10f919..e31b6ae99f 100644
--- a/src/quickvectorimage/generator/qquickgenerator.cpp
+++ b/src/quickvectorimage/generator/qquickgenerator.cpp
@@ -39,10 +39,11 @@ QQuickVectorImageGenerator::GeneratorFlags QQuickGenerator::generatorFlags()
return m_flags;
}
-void QQuickGenerator::generate()
+bool QQuickGenerator::generate()
{
m_loader = new QSvgVisitorImpl(m_fileName, this);
- m_loader->traverse();
+ m_generationSucceeded = m_loader->traverse();
+ return m_generationSucceeded;
}
void QQuickGenerator::optimizePaths(const PathNodeInfo &info)
diff --git a/src/quickvectorimage/generator/qquickgenerator_p.h b/src/quickvectorimage/generator/qquickgenerator_p.h
index c951ad800c..d8ef5c2819 100644
--- a/src/quickvectorimage/generator/qquickgenerator_p.h
+++ b/src/quickvectorimage/generator/qquickgenerator_p.h
@@ -17,9 +17,12 @@
#include <private/qquickvectorimageglobal_p.h>
#include <QtCore/qstring.h>
+#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
+QT_DECLARE_EXPORTED_QT_LOGGING_CATEGORY(lcQuickVectorImage, Q_QUICKVECTORIMAGEGENERATOR_EXPORT)
+
class QSvgVisitorImpl;
class QPainterPath;
class QGradient;
@@ -45,7 +48,7 @@ public:
void setGeneratorFlags(QQuickVectorImageGenerator::GeneratorFlags flags);
QQuickVectorImageGenerator::GeneratorFlags generatorFlags();
- void generate();
+ bool generate();
protected:
virtual void generateNodeBase(const NodeInfo &info) = 0;
@@ -62,6 +65,7 @@ protected:
bool isNodeVisible(const NodeInfo &info);
protected:
+ bool m_generationSucceeded = false;
QQuickVectorImageGenerator::GeneratorFlags m_flags;
private:
diff --git a/src/quickvectorimage/generator/qquickitemgenerator.cpp b/src/quickvectorimage/generator/qquickitemgenerator.cpp
index 171cb6889f..ad85bd3685 100644
--- a/src/quickvectorimage/generator/qquickitemgenerator.cpp
+++ b/src/quickvectorimage/generator/qquickitemgenerator.cpp
@@ -15,8 +15,6 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQuickVectorImage)
-
QQuickItemGenerator::QQuickItemGenerator(const QString fileName, QQuickVectorImageGenerator::GeneratorFlags flags, QQuickItem *parentItem)
:QQuickGenerator(fileName, flags)
{
@@ -75,7 +73,7 @@ void QQuickItemGenerator::generateImageNode(const ImageNodeInfo &info)
auto *imageItem = new QQuickImage;
auto *imagePriv = static_cast<QQuickImageBasePrivate*>(QQuickItemPrivate::get(imageItem));
- imagePriv->pix.setImage(info.image);
+ imagePriv->currentPix->setImage(info.image);
imageItem->setX(info.rect.x());
imageItem->setY(info.rect.y());
@@ -161,6 +159,8 @@ void QQuickItemGenerator::outputShapePath(const PathNodeInfo &info, const QPaint
shapePath->setFillColor(info.fillColor);
shapePath->setFillRule(fillRule);
+ if (!info.fillTransform.isIdentity())
+ shapePath->setFillTransform(info.fillTransform);
QString svgPathString = painterPath ? QQuickVectorImageGenerator::Utils::toSvgString(*painterPath) : QQuickVectorImageGenerator::Utils::toSvgString(*quadPath);
diff --git a/src/quickvectorimage/generator/qquicknodeinfo_p.h b/src/quickvectorimage/generator/qquicknodeinfo_p.h
index 9af3d0b03c..b36f4a59ab 100644
--- a/src/quickvectorimage/generator/qquicknodeinfo_p.h
+++ b/src/quickvectorimage/generator/qquicknodeinfo_p.h
@@ -54,6 +54,19 @@ struct StrokeStyle
QList<qreal> dashArray;
QColor color = QColorConstants::Transparent;
qreal width = 1.0;
+
+ static StrokeStyle fromPen(const QPen &p)
+ {
+ StrokeStyle style;
+ style.lineCapStyle = p.capStyle();
+ style.lineJoinStyle = p.joinStyle() == Qt::SvgMiterJoin ? Qt::MiterJoin : p.joinStyle(); //TODO support SvgMiterJoin
+ style.miterLimit = p.miterLimit();
+ style.dashOffset = p.dashOffset();
+ style.dashArray = p.dashPattern();
+ style.width = p.widthF();
+
+ return style;
+ }
};
struct PathNodeInfo : NodeInfo
@@ -63,6 +76,7 @@ struct PathNodeInfo : NodeInfo
QColor fillColor;
StrokeStyle strokeStyle;
QGradient grad;
+ QTransform fillTransform;
};
struct TextNodeInfo : NodeInfo
diff --git a/src/quickvectorimage/generator/qquickqmlgenerator.cpp b/src/quickvectorimage/generator/qquickqmlgenerator.cpp
index fdb59c7ef4..bd3e781c32 100644
--- a/src/quickvectorimage/generator/qquickqmlgenerator.cpp
+++ b/src/quickvectorimage/generator/qquickqmlgenerator.cpp
@@ -16,80 +16,31 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQuickVectorImage)
-
-class GeneratorStream
-{
-public:
- explicit GeneratorStream(QTextStream *result)
- : m_array(new QByteArray())
- , m_stream(new QTextStream(m_array, QIODeviceBase::ReadWrite))
- , m_resultStream(result)
- {}
-
- ~GeneratorStream()
- {
- if (m_stream) {
- m_stream->flush();
- delete m_stream;
- }
-
- if (m_resultStream && m_array && !m_array->isEmpty())
- *m_resultStream << *m_array << Qt::endl;
-
- delete m_array;
- }
-
- GeneratorStream(GeneratorStream &&other) noexcept
- : m_array(std::exchange(other.m_array, nullptr))
- , m_stream(std::exchange(other.m_stream, nullptr))
- , m_resultStream(std::exchange(other.m_resultStream, nullptr))
- {}
- GeneratorStream &operator=(GeneratorStream &&other) noexcept
- {
- std::swap(m_resultStream, other.m_resultStream);
- std::swap(m_stream, other.m_stream);
- std::swap(m_array, other.m_array);
-
- return *this;
- }
-
- Q_DISABLE_COPY(GeneratorStream)
-private:
- template<typename T>
- friend const GeneratorStream &operator<<(const GeneratorStream& str, T val);
- QByteArray *m_array = nullptr;
- QTextStream *m_stream = nullptr;
- QTextStream *m_resultStream = nullptr;
-};
-
-template<typename T>
-const GeneratorStream &operator<<(const GeneratorStream& str, T val)
-{
- *str.m_stream << val;
- return str;
-}
-
QQuickQmlGenerator::QQuickQmlGenerator(const QString fileName, QQuickVectorImageGenerator::GeneratorFlags flags, const QString &outFileName)
: QQuickGenerator(fileName, flags)
, outputFileName(outFileName)
{
- m_stream = new QTextStream(&result);
+ m_result.open(QIODevice::ReadWrite);
}
QQuickQmlGenerator::~QQuickQmlGenerator()
{
- if (!outputFileName.isEmpty()) {
- QFile outFile(outputFileName);
- outFile.open(QIODevice::WriteOnly);
- outFile.write(result);
- outFile.close();
+ if (m_generationSucceeded && !outputFileName.isEmpty()) {
+ QFileInfo fileInfo(outputFileName);
+ QDir dir(fileInfo.absolutePath());
+ if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) {
+ qCWarning(lcQuickVectorImage) << "Failed to create path" << dir.absolutePath();
+ } else {
+ stream().flush(); // Add a final newline and flush the stream to m_result
+ QFile outFile(outputFileName);
+ outFile.open(QIODevice::WriteOnly);
+ outFile.write(m_result.data());
+ outFile.close();
+ }
}
- if (lcQuickVectorImage().isDebugEnabled()) {
- result.truncate(300);
- qCDebug(lcQuickVectorImage).noquote() << result;
- }
+ if (lcQuickVectorImage().isDebugEnabled())
+ qCDebug(lcQuickVectorImage).noquote() << m_result.data().left(300);
}
void QQuickQmlGenerator::setShapeTypeName(const QString &name)
@@ -127,17 +78,9 @@ void QQuickQmlGenerator::generateNodeBase(const NodeInfo &info)
} else if (info.transform.type() == QTransform::TxScale && !x && !y) {
stream() << "transform: Scale { xScale: " << sx << "; yScale: " << sy << " }";
} else {
- const QMatrix4x4 m(info.transform);
- {
- stream() << "transform: [ Matrix4x4 { matrix: Qt.matrix4x4 (";
- m_indentLevel += 3;
- const auto *data = m.data();
- for (int i = 0; i < 4; i++) {
- stream() << data[i] << ", " << data[i+4] << ", " << data[i+8] << ", " << data[i+12] << ", ";
- }
- stream() << ") } ]";
- m_indentLevel -= 3;
- }
+ stream() << "transform: Matrix4x4 { matrix: ";
+ generateTransform(info.transform);
+ stream(SameLine) << " }";
}
}
if (!info.isDefaultOpacity) {
@@ -269,6 +212,28 @@ void QQuickQmlGenerator::generateGradient(const QGradient *grad, const QRectF &b
}
}
+void QQuickQmlGenerator::generateTransform(const QTransform &xf)
+{
+ if (xf.isAffine()) {
+ stream(SameLine) << "PlanarTransform.fromAffineMatrix("
+ << xf.m11() << ", " << xf.m12() << ", "
+ << xf.m21() << ", " << xf.m22() << ", "
+ << xf.dx() << ", " << xf.dy() << ")";
+ } else {
+ QMatrix4x4 m(xf);
+ stream(SameLine) << "Qt.matrix4x4(";
+ m_indentLevel += 3;
+ const auto *data = m.data();
+ for (int i = 0; i < 4; i++) {
+ stream() << data[i] << ", " << data[i+4] << ", " << data[i+8] << ", " << data[i+12];
+ if (i < 3)
+ stream(SameLine) << ", ";
+ }
+ stream(SameLine) << ")";
+ m_indentLevel -= 3;
+ }
+}
+
void QQuickQmlGenerator::outputShapePath(const PathNodeInfo &info, const QPainterPath *painterPath, const QQuadPath *quadPath, QQuickVectorImageGenerator::PathSelector pathSelector, const QRectF &boundingRect)
{
Q_UNUSED(pathSelector)
@@ -322,6 +287,18 @@ void QQuickQmlGenerator::outputShapePath(const PathNodeInfo &info, const QPainte
} else {
stream() << "fillColor: \"" << info.fillColor.name(QColor::HexArgb) << "\"";
}
+
+ if (!info.fillTransform.isIdentity()) {
+ const QTransform &xf = info.fillTransform;
+ stream() << "fillTransform: ";
+ if (info.fillTransform.type() == QTransform::TxTranslate)
+ stream(SameLine) << "PlanarTransform.fromTranslate(" << xf.dx() << ", " << xf.dy() << ")";
+ else if (info.fillTransform.type() == QTransform::TxScale && !xf.dx() && !xf.dy())
+ stream(SameLine) << "PlanarTransform.fromScale(" << xf.m11() << ", " << xf.m22() << ")";
+ else
+ generateTransform(xf);
+ }
+
if (fillRule == QQuickShapePath::WindingFill)
stream() << "fillRule: ShapePath.WindingFill";
else
@@ -558,16 +535,22 @@ bool QQuickQmlGenerator::generateRootNode(const StructureNodeInfo &info)
return true;
}
-QString QQuickQmlGenerator::indent()
+QStringView QQuickQmlGenerator::indent()
{
- return QString().fill(QLatin1Char(' '), m_indentLevel * 4);
+ static QString indentString;
+ int indentWidth = m_indentLevel * 4;
+ if (indentWidth > indentString.size())
+ indentString.fill(QLatin1Char(' '), indentWidth * 2);
+ return QStringView(indentString).first(indentWidth);
}
-GeneratorStream QQuickQmlGenerator::stream()
+QTextStream &QQuickQmlGenerator::stream(int flags)
{
- GeneratorStream strm(m_stream);
- strm << indent();
- return strm;
+ if (m_stream.device() == nullptr)
+ m_stream.setDevice(&m_result);
+ else if (!(flags & StreamFlags::SameLine))
+ m_stream << Qt::endl << indent();
+ return m_stream;
}
const char *QQuickQmlGenerator::shapeName() const
diff --git a/src/quickvectorimage/generator/qquickqmlgenerator_p.h b/src/quickvectorimage/generator/qquickqmlgenerator_p.h
index 2bef58b054..dae34757b0 100644
--- a/src/quickvectorimage/generator/qquickqmlgenerator_p.h
+++ b/src/quickvectorimage/generator/qquickqmlgenerator_p.h
@@ -18,11 +18,10 @@
#include "qquickgenerator_p.h"
#include <QtCore/qtextstream.h>
+#include <QtCore/qbuffer.h>
QT_BEGIN_NAMESPACE
-class GeneratorStream;
-
class Q_QUICKVECTORIMAGEGENERATOR_EXPORT QQuickQmlGenerator : public QQuickGenerator
{
public:
@@ -79,14 +78,17 @@ protected:
private:
void generateGradient(const QGradient *grad, const QRectF &boundingRect);
- QString indent();
- GeneratorStream stream();
+ void generateTransform(const QTransform &xf);
+
+ QStringView indent();
+ enum StreamFlags { NoFlags = 0x0, SameLine = 0x1 };
+ QTextStream &stream(int flags = NoFlags);
const char *shapeName() const;
private:
int m_indentLevel = 0;
- QTextStream *m_stream;
- QByteArray result;
+ QBuffer m_result;
+ QTextStream m_stream;
QString outputFileName;
bool m_inShapeItem = false;
QByteArray m_shapeTypeName;
diff --git a/src/quickvectorimage/generator/qsvgvisitorimpl.cpp b/src/quickvectorimage/generator/qsvgvisitorimpl.cpp
index ed6dfdf5ea..0717aa21e9 100644
--- a/src/quickvectorimage/generator/qsvgvisitorimpl.cpp
+++ b/src/quickvectorimage/generator/qsvgvisitorimpl.cpp
@@ -25,15 +25,17 @@
#include <private/qquadpath_p.h>
+#include <QtCore/private/qstringiterator_p.h>
+
#include "utils_p.h"
#include <QtCore/qloggingcategory.h>
+#include <QtSvg/private/qsvgstyle_p.h>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-Q_DECLARE_LOGGING_CATEGORY(lcQuickVectorImage)
-
class QSvgStyleResolver
{
public:
@@ -74,6 +76,17 @@ public:
return m_svgState.fillOpacity;
}
+ const QGradient *currentStrokeGradient() const
+ {
+ QBrush brush = m_dummyPainter.pen().brush();
+ if (brush.style() == Qt::LinearGradientPattern
+ || brush.style() == Qt::RadialGradientPattern
+ || brush.style() == Qt::ConicalGradientPattern) {
+ return brush.gradient();
+ }
+ return nullptr;
+ }
+
const QGradient *currentFillGradient() const
{
if (m_dummyPainter.brush().style() == Qt::LinearGradientPattern || m_dummyPainter.brush().style() == Qt::RadialGradientPattern || m_dummyPainter.brush().style() == Qt::ConicalGradientPattern )
@@ -81,6 +94,11 @@ public:
return nullptr;
}
+ QTransform currentFillTransform() const
+ {
+ return m_dummyPainter.brush().transform();
+ }
+
QColor currentStrokeColor() const
{
if (m_dummyPainter.pen().brush().style() == Qt::NoBrush ||
@@ -175,18 +193,68 @@ inline bool isPathContainer(const QSvgStructureNode *node)
return foundPath;
}
-void populateStrokeStyle(StrokeStyle &srokeStyle)
+static QString capStyleName(Qt::PenCapStyle style)
+{
+ QString styleName;
+
+ switch (style) {
+ case Qt::SquareCap:
+ styleName = QStringLiteral("squarecap");
+ break;
+ case Qt::FlatCap:
+ styleName = QStringLiteral("flatcap");
+ break;
+ case Qt::RoundCap:
+ styleName = QStringLiteral("roundcap");
+ break;
+ default:
+ break;
+ }
+
+ return styleName;
+}
+
+static QString joinStyleName(Qt::PenJoinStyle style)
{
- QPen p = styleResolver->currentStroke();
- srokeStyle.lineCapStyle = p.capStyle();
- srokeStyle.lineJoinStyle = p.joinStyle() == Qt::SvgMiterJoin ? Qt::MiterJoin : p.joinStyle(); //TODO support SvgMiterJoin
- srokeStyle.miterLimit = p.miterLimit();
- srokeStyle.dashOffset = p.dashOffset();
- srokeStyle.dashArray = p.dashPattern();
- srokeStyle.color = styleResolver->currentStrokeColor();
- srokeStyle.width = p.widthF();
+ QString styleName;
+
+ switch (style) {
+ case Qt::MiterJoin:
+ styleName = QStringLiteral("miterjoin");
+ break;
+ case Qt::BevelJoin:
+ styleName = QStringLiteral("beveljoin");
+ break;
+ case Qt::RoundJoin:
+ styleName = QStringLiteral("roundjoin");
+ break;
+ case Qt::SvgMiterJoin:
+ styleName = QStringLiteral("svgmiterjoin");
+ break;
+ default:
+ break;
+ }
+
+ return styleName;
}
+static QString dashArrayString(QList<qreal> dashArray)
+{
+ if (dashArray.isEmpty())
+ return QString();
+
+ QString dashArrayString;
+ QTextStream stream(&dashArrayString);
+
+ for (int i = 0; i < dashArray.length() - 1; i++) {
+ qreal value = dashArray[i];
+ stream << value << ", ";
+ }
+
+ stream << dashArray.last();
+
+ return dashArrayString;
+}
};
QSvgVisitorImpl::QSvgVisitorImpl(const QString svgFileName, QQuickGenerator *generator)
@@ -195,20 +263,21 @@ QSvgVisitorImpl::QSvgVisitorImpl(const QString svgFileName, QQuickGenerator *gen
{
}
-void QSvgVisitorImpl::traverse()
+bool QSvgVisitorImpl::traverse()
{
if (!m_generator) {
qCDebug(lcQuickVectorImage) << "No valid QQuickGenerator is set. Genration will stop";
- return;
+ return false;
}
auto *doc = QSvgTinyDocument::load(m_svgFileName);
if (!doc) {
qCDebug(lcQuickVectorImage) << "Not a valid Svg File : " << m_svgFileName;
- return;
+ return false;
}
QSvgVisitor::traverse(doc);
+ return true;
}
void QSvgVisitorImpl::visitNode(const QSvgNode *node)
@@ -361,24 +430,214 @@ QString QSvgVisitorImpl::colorCssDescription(QColor color)
QString cssDescription;
cssDescription += QStringLiteral("rgba(");
cssDescription += QString::number(color.red()) + QStringLiteral(",");
- cssDescription += QString::number(color.blue()) + QStringLiteral(",");
cssDescription += QString::number(color.green()) + QStringLiteral(",");
+ cssDescription += QString::number(color.blue()) + QStringLiteral(",");
cssDescription += QString::number(color.alphaF()) + QStringLiteral(")");
return cssDescription;
}
+namespace {
+
+ // Simple class for representing the SVG font as a font engine
+ // We use the Proxy font engine type, which is currently unused and does not map to
+ // any specific font engine
+ // (The QSvgFont object must outlive the engine.)
+ class QSvgFontEngine : public QFontEngine
+ {
+ public:
+ QSvgFontEngine(const QSvgFont *font, qreal size);
+
+ QFontEngine *cloneWithSize(qreal size) const override;
+
+ glyph_t glyphIndex(uint ucs4) const override;
+ int stringToCMap(const QChar *str,
+ int len,
+ QGlyphLayout *glyphs,
+ int *nglyphs,
+ ShaperFlags flags) const override;
+
+ void addGlyphsToPath(glyph_t *glyphs,
+ QFixedPoint *positions,
+ int nGlyphs,
+ QPainterPath *path,
+ QTextItem::RenderFlags flags) override;
+
+ glyph_metrics_t boundingBox(glyph_t glyph) override;
+
+ void recalcAdvances(QGlyphLayout *, ShaperFlags) const override;
+ QFixed ascent() const override;
+ QFixed capHeight() const override;
+ QFixed descent() const override;
+ QFixed leading() const override;
+ qreal maxCharWidth() const override;
+ qreal minLeftBearing() const override;
+ qreal minRightBearing() const override;
+
+ QFixed emSquareSize() const override;
+
+ private:
+ const QSvgFont *m_font;
+ };
+
+ QSvgFontEngine::QSvgFontEngine(const QSvgFont *font, qreal size)
+ : QFontEngine(Proxy)
+ , m_font(font)
+ {
+ fontDef.pixelSize = size;
+ fontDef.families = QStringList(m_font->m_familyName);
+ }
+
+ QFixed QSvgFontEngine::emSquareSize() const
+ {
+ return QFixed::fromReal(m_font->m_unitsPerEm);
+ }
+
+ glyph_t QSvgFontEngine::glyphIndex(uint ucs4) const
+ {
+ if (ucs4 < USHRT_MAX && m_font->m_glyphs.contains(QChar(ushort(ucs4))))
+ return glyph_t(ucs4);
+
+ return 0;
+ }
+
+ int QSvgFontEngine::stringToCMap(const QChar *str,
+ int len,
+ QGlyphLayout *glyphs,
+ int *nglyphs,
+ ShaperFlags flags) const
+ {
+ Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
+ if (*nglyphs < len) {
+ *nglyphs = len;
+ return -1;
+ }
+
+ int ucs4Length = 0;
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ char32_t ucs4 = it.next();
+ glyph_t index = glyphIndex(ucs4);
+ glyphs->glyphs[ucs4Length++] = index;
+ }
+
+ *nglyphs = ucs4Length;
+ glyphs->numGlyphs = ucs4Length;
+
+ if (!(flags & GlyphIndicesOnly))
+ recalcAdvances(glyphs, flags);
+
+ return *nglyphs;
+ }
+
+ void QSvgFontEngine::addGlyphsToPath(glyph_t *glyphs,
+ QFixedPoint *positions,
+ int nGlyphs,
+ QPainterPath *path,
+ QTextItem::RenderFlags flags)
+ {
+ Q_UNUSED(flags);
+ const qreal scale = fontDef.pixelSize / m_font->m_unitsPerEm;
+ for (int i = 0; i < nGlyphs; ++i) {
+ glyph_t index = glyphs[i];
+ if (index > 0) {
+ QPointF position = positions[i].toPointF();
+ QPainterPath glyphPath = m_font->m_glyphs.value(QChar(ushort(index))).m_path;
+
+ QTransform xform;
+ xform.translate(position.x(), position.y());
+ xform.scale(scale, -scale);
+ glyphPath = xform.map(glyphPath);
+ path->addPath(glyphPath);
+ }
+ }
+ }
+
+ glyph_metrics_t QSvgFontEngine::boundingBox(glyph_t glyph)
+ {
+ glyph_metrics_t ret;
+ ret.x = 0; // left bearing
+ ret.y = -ascent();
+ const qreal scale = fontDef.pixelSize / m_font->m_unitsPerEm;
+ const QSvgGlyph &svgGlyph = m_font->m_glyphs.value(QChar(ushort(glyph)));
+ ret.width = QFixed::fromReal(svgGlyph.m_horizAdvX * scale);
+ ret.height = ascent() + descent();
+ return ret;
+ }
+
+ QFontEngine *QSvgFontEngine::cloneWithSize(qreal size) const
+ {
+ QSvgFontEngine *otherEngine = new QSvgFontEngine(m_font, size);
+ return otherEngine;
+ }
+
+ void QSvgFontEngine::recalcAdvances(QGlyphLayout *glyphLayout, ShaperFlags) const
+ {
+ const qreal scale = fontDef.pixelSize / m_font->m_unitsPerEm;
+ for (int i = 0; i < glyphLayout->numGlyphs; i++) {
+ glyph_t glyph = glyphLayout->glyphs[i];
+ const QSvgGlyph &svgGlyph = m_font->m_glyphs.value(QChar(ushort(glyph)));
+ glyphLayout->advances[i] = QFixed::fromReal(svgGlyph.m_horizAdvX * scale);
+ }
+ }
+
+ QFixed QSvgFontEngine::ascent() const
+ {
+ return QFixed::fromReal(fontDef.pixelSize);
+ }
+
+ QFixed QSvgFontEngine::capHeight() const
+ {
+ return ascent();
+ }
+ QFixed QSvgFontEngine::descent() const
+ {
+ return QFixed{};
+ }
+
+ QFixed QSvgFontEngine::leading() const
+ {
+ return QFixed{};
+ }
+
+ qreal QSvgFontEngine::maxCharWidth() const
+ {
+ const qreal scale = fontDef.pixelSize / m_font->m_unitsPerEm;
+ return m_font->m_horizAdvX * scale;
+ }
+
+ qreal QSvgFontEngine::minLeftBearing() const
+ {
+ return 0.0;
+ }
+
+ qreal QSvgFontEngine::minRightBearing() const
+ {
+ return 0.0;
+ }
+}
+
void QSvgVisitorImpl::visitTextNode(const QSvgText *node)
{
handleBaseNodeSetup(node);
const bool isTextArea = node->type() == QSvgNode::Textarea;
QString text;
+ const QSvgFont *svgFont = styleResolver->states().svgFont;
bool needsRichText = false;
bool preserveWhiteSpace = node->whitespaceMode() == QSvgText::Preserve;
const QGradient *mainGradient = styleResolver->currentFillGradient();
+
+ QFontEngine *fontEngine = nullptr;
+ if (svgFont != nullptr) {
+ fontEngine = new QSvgFontEngine(svgFont, styleResolver->painter().font().pointSize());
+ fontEngine->ref.ref();
+ }
+
#if QT_CONFIG(texthtmlparser)
- bool needsPathNode = mainGradient != nullptr;
+ bool needsPathNode = mainGradient != nullptr
+ || svgFont != nullptr
+ || styleResolver->currentStrokeGradient() != nullptr;
#endif
for (const auto *tspan : node->tspans()) {
if (!tspan) {
@@ -423,10 +682,17 @@ void QSvgVisitorImpl::visitTextNode(const QSvgText *node)
#endif
}
- QString strokeColor = colorCssDescription(styleResolver->currentStrokeColor());
- if (!strokeColor.isEmpty()) {
+ const QColor currentStrokeColor = styleResolver->currentStrokeColor();
+ if (currentStrokeColor.alpha() > 0) {
+ QString strokeColor = colorCssDescription(currentStrokeColor);
styleTagContent += QStringLiteral("-qt-stroke-color:%1;").arg(strokeColor);
- styleTagContent += QStringLiteral("-qt-stroke-width:%1;").arg(styleResolver->currentStrokeWidth());
+ styleTagContent += QStringLiteral("-qt-stroke-width:%1px;").arg(styleResolver->currentStrokeWidth());
+ styleTagContent += QStringLiteral("-qt-stroke-dasharray:%1;").arg(dashArrayString(styleResolver->currentStroke().dashPattern()));
+ styleTagContent += QStringLiteral("-qt-stroke-dashoffset:%1;").arg(styleResolver->currentStroke().dashOffset());
+ styleTagContent += QStringLiteral("-qt-stroke-lineCap:%1;").arg(capStyleName(styleResolver->currentStroke().capStyle()));
+ styleTagContent += QStringLiteral("-qt-stroke-lineJoin:%1;").arg(joinStyleName(styleResolver->currentStroke().joinStyle()));
+ if (styleResolver->currentStroke().joinStyle() == Qt::MiterJoin || styleResolver->currentStroke().joinStyle() == Qt::SvgMiterJoin)
+ styleTagContent += QStringLiteral("-qt-stroke-miterlimit:%1;").arg(styleResolver->currentStroke().miterLimit());
#if QT_CONFIG(texthtmlparser)
needsPathNode = true;
#endif
@@ -468,7 +734,6 @@ void QSvgVisitorImpl::visitTextNode(const QSvgText *node)
if (font.resolveMask() & QFont::StyleResolved && font.italic())
text += QStringLiteral("<i>");
-
if (font.resolveMask() & QFont::CapitalizationResolved) {
switch (font.capitalization()) {
case QFont::AllLowercase:
@@ -523,6 +788,20 @@ void QSvgVisitorImpl::visitTextNode(const QSvgText *node)
QTextLayout *lout = block.layout();
if (lout != nullptr) {
+ // If this block has requested the current SVG font, we override it
+ // (note that this limits the text to one svg font, but this is also the case
+ // in the QPainter at the moment, and needs a more centralized solution in Qt Svg
+ // first)
+ QFont blockFont = block.charFormat().font();
+ if (svgFont != nullptr
+ && blockFont.family() == svgFont->m_familyName) {
+ QRawFont rawFont;
+ QRawFontPrivate *rawFontD = QRawFontPrivate::get(rawFont);
+ rawFontD->setFontEngine(fontEngine->cloneWithSize(blockFont.pixelSize()));
+
+ lout->setRawFont(rawFont);
+ }
+
auto addPathForFormat = [&](QPainterPath p, QTextCharFormat fmt) {
PathNodeInfo info;
fillCommonNodeInfo(node, info);
@@ -540,18 +819,39 @@ void QSvgVisitorImpl::visitTextNode(const QSvgText *node)
info.painterPath = p;
+ const QGradient *strokeGradient = styleResolver->currentStrokeGradient();
+ QPen pen;
if (fmt.hasProperty(QTextCharFormat::TextOutline)) {
- info.strokeStyle.width = fmt.textOutline().widthF();
- info.strokeStyle.color = fmt.textOutline().color();
+ pen = fmt.textOutline();
+ if (strokeGradient == nullptr) {
+ info.strokeStyle = StrokeStyle::fromPen(pen);
+ info.strokeStyle.color = pen.color();
+ }
} else {
- info.strokeStyle.color = styleResolver->currentStrokeColor();
- info.strokeStyle.width = styleResolver->currentStrokeWidth();
+ pen = styleResolver->currentStroke();
+ if (strokeGradient == nullptr) {
+ info.strokeStyle = StrokeStyle::fromPen(pen);
+ info.strokeStyle.color = styleResolver->currentStrokeColor();
+ }
}
if (info.grad.type() == QGradient::NoGradient && styleResolver->currentFillGradient() != nullptr)
info.grad = styleResolver->applyOpacityToGradient(*styleResolver->currentFillGradient(), styleResolver->currentFillOpacity());
+ info.fillTransform = styleResolver->currentFillTransform();
+
m_generator->generatePath(info);
+
+ if (strokeGradient != nullptr) {
+ PathNodeInfo strokeInfo;
+ fillCommonNodeInfo(node, strokeInfo);
+
+ strokeInfo.grad = *strokeGradient;
+
+ QPainterPathStroker stroker(pen);
+ strokeInfo.painterPath = stroker.createStroke(p);
+ m_generator->generatePath(strokeInfo);
+ }
};
qreal baselineOffset = -QFontMetricsF(font).ascent();
@@ -559,9 +859,8 @@ void QSvgVisitorImpl::visitTextNode(const QSvgText *node)
baselineOffset = -lout->lineAt(0).ascent();
const QPointF baselineTranslation(0.0, baselineOffset);
- auto glyphsToPath = [&](QList<QGlyphRun> glyphRuns) {
- QPainterPath path;
- path.setFillRule(Qt::WindingFill);
+ auto glyphsToPath = [&](QList<QGlyphRun> glyphRuns, qreal width) {
+ QList<QPainterPath> paths;
for (const QGlyphRun &glyphRun : glyphRuns) {
QRawFont font = glyphRun.rawFont();
QList<quint32> glyphIndexes = glyphRun.glyphIndexes();
@@ -573,29 +872,25 @@ void QSvgVisitorImpl::visitTextNode(const QSvgText *node)
QPainterPath p = font.pathForGlyph(glyphIndex);
p.translate(pos + node->position() + baselineTranslation);
- path.addPath(p);
+ if (styleResolver->states().textAnchor == Qt::AlignHCenter)
+ p.translate(QPointF(-0.5 * width, 0));
+ else if (styleResolver->states().textAnchor == Qt::AlignRight)
+ p.translate(QPointF(-width, 0));
+ paths.append(p);
}
}
- return path;
+ return paths;
};
QList<QTextLayout::FormatRange> formats = block.textFormats();
for (int i = 0; i < formats.size(); ++i) {
QTextLayout::FormatRange range = formats.at(i);
- // If we hit a "multi" anchor, it means we have additional formats to apply
- // for both this and the subsequent range, so we merge them.
- if (!range.format.anchorNames().isEmpty()
- && range.format.anchorNames().first().startsWith(QStringLiteral("multi"))
- && i < formats.size() - 1) {
- QTextLayout::FormatRange nextRange = formats.at(++i);
- range.length += nextRange.length;
- range.format.merge(nextRange.format);
- }
QList<QGlyphRun> glyphRuns = lout->glyphRuns(range.start, range.length);
- QPainterPath path = glyphsToPath(glyphRuns);
- addPathForFormat(path, range.format);
+ QList<QPainterPath> paths = glyphsToPath(glyphRuns, lout->minimumWidth());
+ for (const QPainterPath &path : paths)
+ addPathForFormat(path, range.format);
}
}
@@ -621,6 +916,12 @@ void QSvgVisitorImpl::visitTextNode(const QSvgText *node)
}
handleBaseNodeEnd(node);
+
+ if (fontEngine != nullptr) {
+ fontEngine->ref.deref();
+ Q_ASSERT(fontEngine->ref.loadRelaxed() == 0);
+ delete fontEngine;
+ }
}
void QSvgVisitorImpl::visitUseNode(const QSvgUse *node)
@@ -664,7 +965,7 @@ bool QSvgVisitorImpl::visitStructureNodeStart(const QSvgStructureNode *node)
info.isPathContainer = isPathContainer(node);
info.stage = StructureNodeStage::Start;
- return m_generator->generateStructureNode(info);;
+ return m_generator->generateStructureNode(info);
}
void QSvgVisitorImpl::visitStructureNodeEnd(const QSvgStructureNode *node)
@@ -693,7 +994,7 @@ bool QSvgVisitorImpl::visitDocumentNodeStart(const QSvgTinyDocument *node)
info.isPathContainer = isPathContainer(node);
info.stage = StructureNodeStage::Start;
- return m_generator->generateRootNode(info);;
+ return m_generator->generateRootNode(info);
}
void QSvgVisitorImpl::visitDocumentNodeEnd(const QSvgTinyDocument *node)
@@ -762,14 +1063,31 @@ void QSvgVisitorImpl::handlePathNode(const QSvgNode *node, const QPainterPath &p
if (fillStyle)
info.fillRule = fillStyle->fillRule();
+ const QGradient *strokeGradient = styleResolver->currentStrokeGradient();
+
info.painterPath = path;
info.fillColor = styleResolver->currentFillColor();
- populateStrokeStyle(info.strokeStyle);
+ if (strokeGradient == nullptr) {
+ info.strokeStyle = StrokeStyle::fromPen(styleResolver->currentStroke());
+ info.strokeStyle.color = styleResolver->currentStrokeColor();
+ }
if (styleResolver->currentFillGradient() != nullptr)
info.grad = styleResolver->applyOpacityToGradient(*styleResolver->currentFillGradient(), styleResolver->currentFillOpacity());
+ info.fillTransform = styleResolver->currentFillTransform();
m_generator->generatePath(info);
+ if (strokeGradient != nullptr) {
+ PathNodeInfo strokeInfo;
+ fillCommonNodeInfo(node, strokeInfo);
+
+ strokeInfo.grad = *strokeGradient;
+
+ QPainterPathStroker stroker(styleResolver->currentStroke());
+ strokeInfo.painterPath = stroker.createStroke(path);
+ m_generator->generatePath(strokeInfo);
+ }
+
handleBaseNodeEnd(node);
}
diff --git a/src/quickvectorimage/generator/qsvgvisitorimpl_p.h b/src/quickvectorimage/generator/qsvgvisitorimpl_p.h
index af8a8d386e..2113510d9b 100644
--- a/src/quickvectorimage/generator/qsvgvisitorimpl_p.h
+++ b/src/quickvectorimage/generator/qsvgvisitorimpl_p.h
@@ -29,7 +29,7 @@ class QSvgVisitorImpl : public QSvgVisitor
{
public:
QSvgVisitorImpl(const QString svgFileName, QQuickGenerator *generator);
- void traverse();
+ bool traverse();
protected:
void visitNode(const QSvgNode *node) override;
diff --git a/src/quickvectorimage/qquickvectorimage.cpp b/src/quickvectorimage/qquickvectorimage.cpp
index b8d93c7691..cd3c0d322e 100644
--- a/src/quickvectorimage/qquickvectorimage.cpp
+++ b/src/quickvectorimage/qquickvectorimage.cpp
@@ -7,6 +7,8 @@
#include <QtQuickVectorImageGenerator/private/qquickvectorimageglobal_p.h>
#include <QtCore/qloggingcategory.h>
+#include <private/qquicktranslate_p.h>
+
QT_BEGIN_NAMESPACE
/*!
@@ -32,8 +34,6 @@ QT_BEGIN_NAMESPACE
\section1 QML Types
*/
-Q_LOGGING_CATEGORY(lcQuickVectorImage, "qt.quick.vectorimage", QtWarningMsg)
-
void QQuickVectorImagePrivate::setSource(const QUrl &source)
{
Q_Q(QQuickVectorImage);
@@ -68,13 +68,17 @@ void QQuickVectorImagePrivate::loadSvg()
svgItem = new QQuickItem(q);
QQuickVectorImageGenerator::GeneratorFlags flags;
- flags.setFlag(QQuickVectorImageGenerator::CurveRenderer);
+ if (preferredRendererType == QQuickVectorImage::CurveRenderer)
+ flags.setFlag(QQuickVectorImageGenerator::CurveRenderer);
QQuickItemGenerator generator(localFile, flags, svgItem);
generator.generate();
svgItem->setParentItem(q);
q->setImplicitWidth(svgItem->width());
q->setImplicitHeight(svgItem->height());
+
+ q->updateSvgItemScale();
+
q->update();
}
@@ -111,6 +115,10 @@ QQuickVectorImage::QQuickVectorImage(QQuickItem *parent)
: QQuickItem(*(new QQuickVectorImagePrivate), parent)
{
setFlag(QQuickItem::ItemHasContents, true);
+
+ QObject::connect(this, &QQuickItem::widthChanged, this, &QQuickVectorImage::updateSvgItemScale);
+ QObject::connect(this, &QQuickItem::heightChanged, this, &QQuickVectorImage::updateSvgItemScale);
+ QObject::connect(this, &QQuickVectorImage::fillModeChanged, this, &QQuickVectorImage::updateSvgItemScale);
}
/*!
@@ -132,4 +140,114 @@ void QQuickVectorImage::setSource(const QUrl &source)
d->setSource(source);
}
+void QQuickVectorImage::updateSvgItemScale()
+{
+ Q_D(QQuickVectorImage);
+
+ if (d->svgItem == nullptr
+ || qFuzzyIsNull(d->svgItem->width())
+ || qFuzzyIsNull(d->svgItem->height())) {
+ return;
+ }
+
+ auto xformProp = d->svgItem->transform();
+ QQuickScale *scaleTransform = nullptr;
+ if (xformProp.count(&xformProp) == 0) {
+ scaleTransform = new QQuickScale;
+ scaleTransform->setParent(d->svgItem);
+ xformProp.append(&xformProp, scaleTransform);
+ } else {
+ scaleTransform = qobject_cast<QQuickScale *>(xformProp.at(&xformProp, 0));
+ }
+
+ if (scaleTransform != nullptr) {
+ qreal xScale = width() / d->svgItem->width();
+ qreal yScale = height() / d->svgItem->height();
+
+ switch (d->fillMode) {
+ case QQuickVectorImage::NoResize:
+ xScale = yScale = 1.0;
+ break;
+ case QQuickVectorImage::PreserveAspectFit:
+ xScale = yScale = qMin(xScale, yScale);
+ break;
+ case QQuickVectorImage::PreserveAspectCrop:
+ xScale = yScale = qMax(xScale, yScale);
+ break;
+ case QQuickVectorImage::Stretch:
+ // Already correct
+ break;
+ };
+
+ scaleTransform->setXScale(xScale);
+ scaleTransform->setYScale(yScale);
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.VectorImage::VectorImage::fillMode
+
+ This property defines what happens if the width and height of the VectorImage differs from
+ the implicit size of its contents.
+
+ \value VectorImage.NoResize The contents are still rendered at the size provided by
+ the input.
+ \value VectorImage.Stretch The contents are scaled to match the width and height of
+ the \c{VectorImage}. (This is the default.)
+ \value VectorImage.PreserveAspectFit The contents are scaled to fit inside the bounds of the
+ \c VectorImage, while preserving aspect ratio. The
+ actual bounding rect of the contents will sometimes be
+ smaller than the \c VectorImage item.
+ \value VectorImage.PreserveAspectCrop The contents are scaled to fill the \c VectorImage item,
+ while preserving the aspect ratio. The actual bounds of
+ the contents will sometimes be larger than the
+ \c VectorImage item.
+*/
+
+QQuickVectorImage::FillMode QQuickVectorImage::fillMode() const
+{
+ Q_D(const QQuickVectorImage);
+ return d->fillMode;
+}
+
+void QQuickVectorImage::setFillMode(FillMode newFillMode)
+{
+ Q_D(QQuickVectorImage);
+ if (d->fillMode == newFillMode)
+ return;
+ d->fillMode = newFillMode;
+ emit fillModeChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.VectorImage::VectorImage::preferredRendererType
+
+ Requests a specific backend to use for rendering shapes in the \c VectorImage.
+
+ \value VectorImage.GeometryRenderer Equivalent to Shape.GeometryRenderer. This backend flattens
+ curves and triangulates the result. It will give aliased results unless multi-sampling is
+ enabled, and curve flattening may be visible when the item is scaled.
+ \value VectorImage.CurveRenderer Equivalent to Shape.CurveRenderer. With this backend, curves
+ are rendered on the GPU and anti-aliasing is built in. Will typically give better visual
+ results, but at some extra cost to performance.
+
+ The default is \c{VectorImage.GeometryRenderer}.
+*/
+
+QQuickVectorImage::RendererType QQuickVectorImage::preferredRendererType() const
+{
+ Q_D(const QQuickVectorImage);
+ return d->preferredRendererType;
+}
+
+void QQuickVectorImage::setPreferredRendererType(RendererType newPreferredRendererType)
+{
+ Q_D(QQuickVectorImage);
+ if (d->preferredRendererType == newPreferredRendererType)
+ return;
+ d->preferredRendererType = newPreferredRendererType;
+ d->loadSvg();
+ emit preferredRendererTypeChanged();
+}
+
QT_END_NAMESPACE
diff --git a/src/quickvectorimage/qquickvectorimage_p.h b/src/quickvectorimage/qquickvectorimage_p.h
index 68ccc561a1..cce935d3ea 100644
--- a/src/quickvectorimage/qquickvectorimage_p.h
+++ b/src/quickvectorimage/qquickvectorimage_p.h
@@ -27,16 +27,44 @@ class Q_QUICKVECTORIMAGE_EXPORT QQuickVectorImage : public QQuickItem
Q_OBJECT
Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged)
+ Q_PROPERTY(RendererType preferredRendererType READ preferredRendererType WRITE setPreferredRendererType NOTIFY preferredRendererTypeChanged)
QML_NAMED_ELEMENT(VectorImage)
public:
+ enum FillMode {
+ NoResize,
+ PreserveAspectFit,
+ PreserveAspectCrop,
+ Stretch
+ };
+ Q_ENUM(FillMode)
+
+ enum RendererType {
+ GeometryRenderer,
+ CurveRenderer
+ };
+ Q_ENUM(RendererType)
+
QQuickVectorImage(QQuickItem *parent = nullptr);
QUrl source() const;
void setSource(const QUrl &source);
+ FillMode fillMode() const;
+ void setFillMode(FillMode newFillMode);
+
+ RendererType preferredRendererType() const;
+ void setPreferredRendererType(RendererType newPreferredRendererType);
+
signals:
void sourceChanged();
+ void fillModeChanged();
+
+ void preferredRendererTypeChanged();
+
+private slots:
+ void updateSvgItemScale();
private:
Q_DISABLE_COPY(QQuickVectorImage)
diff --git a/src/quickvectorimage/qquickvectorimage_p_p.h b/src/quickvectorimage/qquickvectorimage_p_p.h
index 689a5e9b69..4ad408b628 100644
--- a/src/quickvectorimage/qquickvectorimage_p_p.h
+++ b/src/quickvectorimage/qquickvectorimage_p_p.h
@@ -40,6 +40,8 @@ public:
QUrl sourceFile;
QQuickItem *svgItem = nullptr;
+ QQuickVectorImage::FillMode fillMode = QQuickVectorImage::Stretch;
+ QQuickVectorImage::RendererType preferredRendererType = QQuickVectorImage::GeometryRenderer;
};
QT_END_NAMESPACE
diff --git a/src/quickwidgets/CMakeLists.txt b/src/quickwidgets/CMakeLists.txt
index aa7a682343..f3575c84fc 100644
--- a/src/quickwidgets/CMakeLists.txt
+++ b/src/quickwidgets/CMakeLists.txt
@@ -33,7 +33,6 @@ qt_internal_add_module(QuickWidgets
Qt::QmlPrivate
Qt::QuickPrivate
Qt::WidgetsPrivate
- GENERATE_CPP_EXPORTS
)
qt_internal_extend_target(QuickWidgets CONDITION QT_FEATURE_accessibility
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index c782dc74b1..130b7677e6 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -276,9 +276,7 @@ void QQuickWidgetPrivate::handleWindowChange()
QObject::connect(renderControl, SIGNAL(renderRequested()), q, SLOT(triggerUpdate()));
QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
- if (!source.isEmpty())
- execute();
- else if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(root))
+ if (QQuickItem *sgItem = qobject_cast<QQuickItem *>(root))
sgItem->setParentItem(offscreenWindow->contentItem());
}
@@ -1313,12 +1311,6 @@ QPlatformBackingStoreRhiConfig QQuickWidgetPrivate::rhiConfig() const
QWidgetPrivate::TextureData QQuickWidgetPrivate::texture() const
{
- Q_Q(const QQuickWidget);
- if (!q->isWindow() && q->internalWinId()) {
- qWarning() << "QQuickWidget cannot be used as a native child widget."
- << "Consider setting Qt::AA_DontCreateNativeWidgetSiblings";
- return {};
- }
return { outputTexture, nullptr };
}
diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt
index 0e168cf6ad..4a86e71e59 100644
--- a/tests/auto/cmake/CMakeLists.txt
+++ b/tests/auto/cmake/CMakeLists.txt
@@ -125,10 +125,17 @@ if(TARGET Qt::Qml)
set(test_static_qml_module_extra_args "")
endif()
_qt_internal_test_expect_pass(test_static_qml_module ${test_static_qml_module_extra_args})
+ _qt_internal_test_expect_pass(test_javascript_files TESTNAME cmake_test_javascript_files)
+ set_tests_properties(cmake_test_javascript_files PROPERTIES
+ FAIL_REGULAR_EXPRESSION "(Good\.js|good\.js|Included\.js|Excluded\.js|Good\.mjs) is not an ECMAScript module"
+ PASS_REGULAR_EXPRESSION "Bad\.js is not an ECMAScript module"
+ )
+
endif()
if(TARGET Qt::Quick)
if(NOT CMAKE_CROSSCOMPILING)
+ _qt_internal_test_expect_pass(shared_qml_module)
_qt_internal_test_expect_pass(qtquickcompiler BINARY qqc_test)
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.21")
_qt_internal_test_expect_pass(test_common_import_path
diff --git a/tests/auto/cmake/shared_qml_module/CMakeLists.txt b/tests/auto/cmake/shared_qml_module/CMakeLists.txt
new file mode 100644
index 0000000000..867caa4aad
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(scheduler VERSION 0.1 LANGUAGES CXX)
+
+find_package(Qt6 REQUIRED COMPONENTS Qml)
+qt_standard_project_setup(REQUIRES 6.8)
+
+add_custom_target(custom_qmllint_target ALL)
+set(QT_QMLLINT_ALL_TARGET custom_qmllint_target)
+
+add_subdirectory(external)
+add_subdirectory(Scheduler)
+add_subdirectory(SchedulerApp)
+add_subdirectory(tests)
diff --git a/tests/auto/cmake/shared_qml_module/Scheduler/CMakeLists.txt b/tests/auto/cmake/shared_qml_module/Scheduler/CMakeLists.txt
new file mode 100644
index 0000000000..a40688d3a3
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/Scheduler/CMakeLists.txt
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(scheduler VERSION 0.1 LANGUAGES CXX)
+
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(Qt6 6.5 REQUIRED COMPONENTS Quick)
+
+qt_add_qml_module(scheduler
+ URI Scheduler
+ VERSION 1.0
+ SOURCES
+ task.h
+ task.cpp
+ schedulerglobal.h
+ QML_FILES
+ MainScreen.qml
+)
+
+target_compile_definitions(scheduler
+ PRIVATE
+ SCHEDULER_LIBRARY
+)
+
+target_include_directories(scheduler
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+target_link_libraries(scheduler
+ PRIVATE
+ Qt6::Quick
+)
diff --git a/tests/auto/cmake/shared_qml_module/Scheduler/MainScreen.qml b/tests/auto/cmake/shared_qml_module/Scheduler/MainScreen.qml
new file mode 100644
index 0000000000..6260b4f918
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/Scheduler/MainScreen.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Rectangle {
+ color: "tomato"
+}
diff --git a/tests/auto/cmake/shared_qml_module/Scheduler/schedulerglobal.h b/tests/auto/cmake/shared_qml_module/Scheduler/schedulerglobal.h
new file mode 100644
index 0000000000..cd24bcc8b9
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/Scheduler/schedulerglobal.h
@@ -0,0 +1,15 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef SCHEDULEGLOBAL_H
+#define SCHEDULEGLOBAL_H
+
+#include <QtGlobal>
+
+#if defined(SCHEDULER_LIBRARY)
+#define SCHEDULER_EXPORT Q_DECL_EXPORT
+#else
+#define SCHEDULER_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // SCHEDULEGLOBAL_H
diff --git a/tests/auto/cmake/shared_qml_module/Scheduler/task.cpp b/tests/auto/cmake/shared_qml_module/Scheduler/task.cpp
new file mode 100644
index 0000000000..534a614139
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/Scheduler/task.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "task.h"
+
+Task::Task()
+{
+}
+
+Task::Task(const QString &name, int durationInMinutes)
+ : mName(name)
+ , mDurationInMinutes(durationInMinutes)
+{
+}
+
+QString Task::name() const
+{
+ return mName;
+}
+
+void Task::setName(const QString &name)
+{
+ mName = name;
+}
+
+int Task::durationInMinutes() const
+{
+ return mDurationInMinutes;
+}
+
+void Task::setDurationInMinutes(int durationInMinutes)
+{
+ mDurationInMinutes = durationInMinutes;
+}
+
+bool Task::read(const QJsonObject &json)
+{
+ mName = json.value("name").toString();
+ mDurationInMinutes = json.value("durationInMinutes").toInt();
+ return true;
+}
+
+void Task::write(QJsonObject &json) const
+{
+ json["name"] = mName;
+ json["durationInMinutes"] = mDurationInMinutes;
+}
diff --git a/tests/auto/cmake/shared_qml_module/Scheduler/task.h b/tests/auto/cmake/shared_qml_module/Scheduler/task.h
new file mode 100644
index 0000000000..916f939508
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/Scheduler/task.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef TASK_H
+#define TASK_H
+
+#include <QObject>
+#include <QJsonObject>
+
+#include "schedulerglobal.h"
+
+class SCHEDULER_EXPORT Task : public QObject
+{
+ Q_OBJECT
+
+public:
+ Task();
+ Task(const QString &name, int durationInMinutes);
+
+ bool read(const QJsonObject &json);
+ void write(QJsonObject &json) const;
+
+ QString name() const;
+ void setName(const QString &name);
+
+ int durationInMinutes() const;
+ void setDurationInMinutes(int durationInMinutes);
+
+private:
+ QString mName;
+ int mDurationInMinutes = 0;
+};
+
+#endif // TASK_H
diff --git a/tests/auto/cmake/shared_qml_module/SchedulerApp/CMakeLists.txt b/tests/auto/cmake/shared_qml_module/SchedulerApp/CMakeLists.txt
new file mode 100644
index 0000000000..fdbb1df701
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/SchedulerApp/CMakeLists.txt
@@ -0,0 +1,44 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(schedulerapp VERSION 0.1 LANGUAGES CXX)
+
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(Qt6 6.5 REQUIRED COMPONENTS Quick)
+
+qt_add_executable(schedulerapp
+ main.cpp
+)
+
+qt_add_qml_module(schedulerapp
+ URI SchedulerApp
+ DEPENDENCIES
+ TARGET scheduler
+ IMPORTS
+ TARGET nested_module
+ VERSION 1.0
+ QML_FILES
+ Main.qml
+)
+
+# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
+# If you are developing for iOS or macOS you should consider setting an
+# explicit, fixed bundle identifier manually though.
+set_target_properties(schedulerapp PROPERTIES
+# MACOSX_BUNDLE_GUI_IDENTIFIER com.example.schedulerapp
+ MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
+ MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
+ MACOSX_BUNDLE TRUE
+ WIN32_EXECUTABLE TRUE
+)
+
+target_link_libraries(schedulerapp
+ PRIVATE Qt6::Quick
+)
+
+include(GNUInstallDirs)
+install(TARGETS schedulerapp
+ BUNDLE DESTINATION .
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
diff --git a/tests/auto/cmake/shared_qml_module/SchedulerApp/Main.qml b/tests/auto/cmake/shared_qml_module/SchedulerApp/Main.qml
new file mode 100644
index 0000000000..4dddb35ae8
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/SchedulerApp/Main.qml
@@ -0,0 +1,12 @@
+import QtQuick.Controls
+import Scheduler
+
+ApplicationWindow {
+ width: 640
+ height: 480
+ visible: true
+ title: qsTr("Scheduler")
+
+ MainScreen {}
+ Test {}
+}
diff --git a/tests/auto/cmake/shared_qml_module/SchedulerApp/main.cpp b/tests/auto/cmake/shared_qml_module/SchedulerApp/main.cpp
new file mode 100644
index 0000000000..6422d91bfa
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/SchedulerApp/main.cpp
@@ -0,0 +1,21 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+//
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ qputenv("QT_QUICK_CONTROLS_STYLE", "Material");
+
+ QQmlApplicationEngine engine;
+ QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
+ &app, []() { QCoreApplication::exit(-1); },
+ Qt::QueuedConnection);
+ engine.loadFromModule("SchedulerApp", "Main");
+
+ return app.exec();
+}
diff --git a/tests/auto/cmake/shared_qml_module/external/CMakeLists.txt b/tests/auto/cmake/shared_qml_module/external/CMakeLists.txt
new file mode 100644
index 0000000000..798a23e1a5
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/external/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(nested/module)
diff --git a/tests/auto/cmake/shared_qml_module/external/nested/module/CMakeLists.txt b/tests/auto/cmake/shared_qml_module/external/nested/module/CMakeLists.txt
new file mode 100644
index 0000000000..da75d2333a
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/external/nested/module/CMakeLists.txt
@@ -0,0 +1,15 @@
+
+cmake_minimum_required(VERSION 3.16)
+
+project(scheduler VERSION 0.1 LANGUAGES CXX)
+
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(Qt6 6.5 REQUIRED COMPONENTS Quick)
+
+qt_add_qml_module(nested_module
+ URI nested.module
+ VERSION 1.0
+ QML_FILES
+ Test.qml
+)
diff --git a/tests/auto/cmake/shared_qml_module/external/nested/module/Test.qml b/tests/auto/cmake/shared_qml_module/external/nested/module/Test.qml
new file mode 100644
index 0000000000..3052615aef
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/external/nested/module/Test.qml
@@ -0,0 +1,3 @@
+import QtQuick
+
+Item {}
diff --git a/tests/auto/cmake/shared_qml_module/tests/CMakeLists.txt b/tests/auto/cmake/shared_qml_module/tests/CMakeLists.txt
new file mode 100644
index 0000000000..0653827192
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/tests/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(auto)
diff --git a/tests/auto/cmake/shared_qml_module/tests/auto/CMakeLists.txt b/tests/auto/cmake/shared_qml_module/tests/auto/CMakeLists.txt
new file mode 100644
index 0000000000..269aea0c60
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/tests/auto/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(unit)
diff --git a/tests/auto/cmake/shared_qml_module/tests/auto/unit/CMakeLists.txt b/tests/auto/cmake/shared_qml_module/tests/auto/unit/CMakeLists.txt
new file mode 100644
index 0000000000..9d5f1d9f5e
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/tests/auto/unit/CMakeLists.txt
@@ -0,0 +1,40 @@
+cmake_minimum_required(VERSION 3.5)
+
+project(tst_models LANGUAGES CXX)
+
+enable_testing()
+
+find_package(Qt6 REQUIRED COMPONENTS Gui Test Quick)
+
+set(CMAKE_AUTOUIC ON)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+add_executable(tst_models tst_models.cpp)
+add_test(NAME tst_models COMMAND tst_models)
+
+target_link_libraries(tst_models
+ PRIVATE
+ scheduler
+ Qt6::Gui
+ Qt6::Test
+ Qt6::Quick
+)
+
+
+qt_add_qml_module(tst_models
+ URI unittest
+ DEPENDENCIES
+ TARGET scheduler
+)
+
+
+qt_add_executable(tst_models_dummy_helper dummy.cpp)
+qt_add_qml_module(tst_models_dummy_helper
+ URI unimportant
+ DEPENDENCIES
+ TARGET nested_module
+)
diff --git a/tests/auto/cmake/shared_qml_module/tests/auto/unit/dummy.cpp b/tests/auto/cmake/shared_qml_module/tests/auto/unit/dummy.cpp
new file mode 100644
index 0000000000..237c8ce181
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/tests/auto/unit/dummy.cpp
@@ -0,0 +1 @@
+int main() {}
diff --git a/tests/auto/cmake/shared_qml_module/tests/auto/unit/tst_models.cpp b/tests/auto/cmake/shared_qml_module/tests/auto/unit/tst_models.cpp
new file mode 100644
index 0000000000..0a7119fbcc
--- /dev/null
+++ b/tests/auto/cmake/shared_qml_module/tests/auto/unit/tst_models.cpp
@@ -0,0 +1,45 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest>
+
+
+class tst_models : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_models();
+ ~tst_models();
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+
+ void qtconf();
+};
+
+tst_models::tst_models() {}
+
+tst_models::~tst_models() {}
+
+void tst_models::initTestCase() {}
+
+void tst_models::cleanupTestCase() {}
+
+void tst_models::qtconf()
+{
+ auto importPaths = QLibraryInfo::paths(QLibraryInfo::QmlImportsPath);
+ QCOMPARE_GE(importPaths.size(), 2);
+ if (importPaths.at(0).endsWith("shared_qml_module")) {
+ QVERIFY(importPaths.at(1).endsWith("external/nested"));
+ } else if (importPaths.at(0).endsWith("external/nested")) {
+ QVERIFY(importPaths.at(1).endsWith("shared_qml_module"));
+ } else {
+ QFAIL("Expected import paths were not found");
+ }
+}
+
+QTEST_MAIN(tst_models)
+
+#include "tst_models.moc"
diff --git a/tests/auto/cmake/test_generate_qmlls_ini/main.cpp b/tests/auto/cmake/test_generate_qmlls_ini/main.cpp
index a7bdbf1e18..2d663cdc23 100644
--- a/tests/auto/cmake/test_generate_qmlls_ini/main.cpp
+++ b/tests/auto/cmake/test_generate_qmlls_ini/main.cpp
@@ -5,6 +5,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qdir.h>
#include <QtCore/qfile.h>
+#include <QtCore/qlibraryinfo.h>
#include <QtQml/qqml.h>
#include <QtTest/qtest.h>
@@ -33,6 +34,7 @@ void tst_generate_qmlls_ini::qmllsIniAreCorrect()
QSKIP(u"Cannot find source directory '%1', skipping test..."_s.arg(SOURCE_DIRECTORY)
.toLatin1());
+ const QString &docPath = QLibraryInfo::path(QLibraryInfo::DocumentationPath);
{
auto file = QFile(source.absoluteFilePath(qmllsIniName));
QVERIFY(file.exists());
@@ -41,8 +43,8 @@ void tst_generate_qmlls_ini::qmllsIniAreCorrect()
auto secondFolder = QDir(build.absolutePath().append(u"/qml/hello/subfolders"_s));
QVERIFY(secondFolder.exists());
QCOMPARE(fileContent,
- u"[General]\nbuildDir=%1%2%3\nno-cmake-calls=false\n"_s.arg(build.absolutePath(), QDir::listSeparator(),
- secondFolder.absolutePath()));
+ u"[General]\nbuildDir=%1%2%3\nno-cmake-calls=false\ndocDir=%4\n"_s.arg(build.absolutePath(), QDir::listSeparator(),
+ secondFolder.absolutePath(), docPath));
}
{
@@ -55,7 +57,7 @@ void tst_generate_qmlls_ini::qmllsIniAreCorrect()
QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
const auto fileContent = QString::fromUtf8(file.readAll());
QCOMPARE(fileContent,
- u"[General]\nbuildDir=%1\nno-cmake-calls=false\n"_s.arg(buildSubfolder.absolutePath()));
+ u"[General]\nbuildDir=%1\nno-cmake-calls=false\ndocDir=%2\n"_s.arg(buildSubfolder.absolutePath(), docPath));
}
}
@@ -70,7 +72,7 @@ void tst_generate_qmlls_ini::qmllsIniAreCorrect()
const auto fileContent = QString::fromUtf8(file.readAll());
QCOMPARE(
fileContent,
- u"[General]\nbuildDir=%1\nno-cmake-calls=false\n"_s.arg(build.absolutePath()));
+ u"[General]\nbuildDir=%1\nno-cmake-calls=false\ndocDir=%2\n"_s.arg(build.absolutePath(), docPath));
}
}
{
@@ -86,7 +88,7 @@ void tst_generate_qmlls_ini::qmllsIniAreCorrect()
const auto fileContent = QString::fromUtf8(file.readAll());
QCOMPARE(
fileContent,
- u"[General]\nbuildDir=%1\nno-cmake-calls=false\n"_s.arg(build.absolutePath()));
+ u"[General]\nbuildDir=%1\nno-cmake-calls=false\ndocDir=%2\n"_s.arg(build.absolutePath(), docPath));
}
}
}
diff --git a/tests/auto/cmake/test_javascript_files/Bad.js b/tests/auto/cmake/test_javascript_files/Bad.js
new file mode 100644
index 0000000000..0a355ab868
--- /dev/null
+++ b/tests/auto/cmake/test_javascript_files/Bad.js
@@ -0,0 +1 @@
+var a = 5
diff --git a/tests/auto/cmake/test_javascript_files/CMakeLists.txt b/tests/auto/cmake/test_javascript_files/CMakeLists.txt
new file mode 100644
index 0000000000..f843000c72
--- /dev/null
+++ b/tests/auto/cmake/test_javascript_files/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+cmake_minimum_required(VERSION 3.16)
+
+project(test_javascript_files)
+
+find_package(Qt6 REQUIRED COMPONENTS Qml)
+
+qt_standard_project_setup(REQUIRES 6.8)
+
+set_source_files_properties(Excluded.js PROPERTIES
+ QT_QML_SKIP_QMLDIR_ENTRY TRUE
+)
+
+set_source_files_properties(Included.js PROPERTIES
+ QT_QML_SKIP_QMLDIR_ENTRY FALSE
+)
+
+qt_add_qml_module(javascript_files
+ URI test_javascript_files
+ QML_FILES
+ Bad.js
+ Good.js
+ Good.mjs
+ Excluded.js
+ Included.js
+ lower.js
+)
diff --git a/tests/auto/cmake/test_javascript_files/Excluded.js b/tests/auto/cmake/test_javascript_files/Excluded.js
new file mode 100644
index 0000000000..c12ad02b1c
--- /dev/null
+++ b/tests/auto/cmake/test_javascript_files/Excluded.js
@@ -0,0 +1 @@
+var a = 6
diff --git a/tests/auto/cmake/test_javascript_files/Good.js b/tests/auto/cmake/test_javascript_files/Good.js
new file mode 100644
index 0000000000..4e19c461bd
--- /dev/null
+++ b/tests/auto/cmake/test_javascript_files/Good.js
@@ -0,0 +1,3 @@
+.pragma library
+
+var a = 7
diff --git a/tests/auto/cmake/test_javascript_files/Good.mjs b/tests/auto/cmake/test_javascript_files/Good.mjs
new file mode 100644
index 0000000000..27dd801cc0
--- /dev/null
+++ b/tests/auto/cmake/test_javascript_files/Good.mjs
@@ -0,0 +1 @@
+var a = 8
diff --git a/tests/auto/cmake/test_javascript_files/Included.js b/tests/auto/cmake/test_javascript_files/Included.js
new file mode 100644
index 0000000000..c731b8d5c4
--- /dev/null
+++ b/tests/auto/cmake/test_javascript_files/Included.js
@@ -0,0 +1 @@
+var a = 9
diff --git a/tests/auto/cmake/test_javascript_files/lower.js b/tests/auto/cmake/test_javascript_files/lower.js
new file mode 100644
index 0000000000..0dd32430e9
--- /dev/null
+++ b/tests/auto/cmake/test_javascript_files/lower.js
@@ -0,0 +1 @@
+var a = 10
diff --git a/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp b/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp
index 9e5bc17623..97477370c8 100644
--- a/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp
+++ b/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp
@@ -56,7 +56,7 @@ QString QQmlDebugProcess::stateString() const
void QQmlDebugProcess::start(const QStringList &arguments)
{
-#ifdef Q_OS_MAC
+#ifdef Q_OS_MACOS
// make sure m_executable points to the actual binary even if it's inside an app bundle
QFileInfo binFile(m_executable);
if (!binFile.isExecutable()) {
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index 2e96de7819..cc5eae456d 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -98,7 +98,6 @@ built-ins/Array/prototype/slice/length-exceeding-integer-limit-proxied-array.js
built-ins/Array/prototype/slice/length-exceeding-integer-limit.js fails
built-ins/Array/prototype/some/15.4.4.17-3-28.js fails
built-ins/Array/prototype/some/15.4.4.17-3-29.js fails
-built-ins/Array/prototype/sort/comparefn-nonfunction-call-throws.js fails
built-ins/Array/prototype/splice/S15.4.4.12_A3_T1.js fails
built-ins/Array/prototype/splice/clamps-length-to-integer-limit.js fails
built-ins/Array/prototype/splice/create-ctor-non-object.js fails
@@ -254,8 +253,6 @@ built-ins/String/prototype/toLocaleLowerCase/special_casing_conditional.js fails
built-ins/String/prototype/toLowerCase/Final_Sigma_U180E.js fails
built-ins/String/prototype/toLowerCase/special_casing_conditional.js fails
built-ins/TypedArray/prototype/constructor.js fails
-built-ins/TypedArray/prototype/fill/fill-values-conversion-operations-consistent-nan.js fails
-built-ins/TypedArray/prototype/slice/bit-precision.js fails
built-ins/TypedArray/prototype/sort/arraylength-internal.js fails
built-ins/TypedArray/prototype/sort/comparefn-call-throws.js fails
built-ins/TypedArray/prototype/sort/comparefn-calls.js fails
diff --git a/tests/auto/qml/ecmascripttests/test262runner.cpp b/tests/auto/qml/ecmascripttests/test262runner.cpp
index dc6d660e3d..ff45b1b657 100644
--- a/tests/auto/qml/ecmascripttests/test262runner.cpp
+++ b/tests/auto/qml/ecmascripttests/test262runner.cpp
@@ -89,9 +89,7 @@ void initD262(ExecutionEngine *e)
}
-
-Q_DECLARE_LOGGING_CATEGORY(lcJsTest);
-Q_LOGGING_CATEGORY(lcJsTest, "qt.v4.ecma262.tests", QtWarningMsg);
+Q_STATIC_LOGGING_CATEGORY(lcJsTest, "qt.v4.ecma262.tests", QtWarningMsg);
Test262Runner::Test262Runner(const QString &command, const QString &dir, const QString &expectationsFile)
: command(command), testDir(dir), expectationsFile(expectationsFile)
@@ -223,8 +221,8 @@ void Test262Runner::createProcesses()
});
QObject::connect(&p, &QProcess::finished, this,
- [this, processCount, i](int, QProcess::ExitStatus status) {
- if (status != QProcess::NormalExit) {
+ [this, processCount, i](int exitCode, QProcess::ExitStatus status) {
+ if (status != QProcess::NormalExit || exitCode != 0) {
TestData &testData(currentTasks[i]);
auto &result = testData.stillNeedStrictRun
diff --git a/tests/auto/qml/linebylinelex/BLACKLIST b/tests/auto/qml/linebylinelex/BLACKLIST
deleted file mode 100644
index 0fd7f604e3..0000000000
--- a/tests/auto/qml/linebylinelex/BLACKLIST
+++ /dev/null
@@ -1,5 +0,0 @@
-# QTBUG-105697
-[testFormatter]
-android
-[testLineByLineLex]
-android
diff --git a/tests/auto/qml/linebylinelex/CMakeLists.txt b/tests/auto/qml/linebylinelex/CMakeLists.txt
index 8b05ca0527..92d956a972 100644
--- a/tests/auto/qml/linebylinelex/CMakeLists.txt
+++ b/tests/auto/qml/linebylinelex/CMakeLists.txt
@@ -10,12 +10,12 @@ endif()
# Collect linebyline test data
file(GLOB_RECURSE test_data_glob
- RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/..
- linebylinelex/data/*)
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
# Collect qmlformat test data
file(GLOB_RECURSE test_data_glob2
- RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/..
- qmlformat/data/*)
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ ../qmlformat/data/*)
list(APPEND test_data ${test_data_glob} ${test_data_glob2})
qt_internal_add_test(tst_linebylinelex
@@ -25,17 +25,5 @@ qt_internal_add_test(tst_linebylinelex
Qt::Qml
Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
-)
-
-## Scopes:
-#####################################################################
-
-qt_internal_extend_target(tst_linebylinelex CONDITION ANDROID OR IOS
- DEFINES
- QT_QMLTEST_DATADIR=":/"
-)
-
-qt_internal_extend_target(tst_linebylinelex CONDITION NOT ANDROID AND NOT IOS
- DEFINES
- QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/.."
+ BUILTIN_TESTDATA
)
diff --git a/tests/auto/qml/linebylinelex/tst_linebylinelex.cpp b/tests/auto/qml/linebylinelex/tst_linebylinelex.cpp
index d94f325020..040ccfa9a6 100644
--- a/tests/auto/qml/linebylinelex/tst_linebylinelex.cpp
+++ b/tests/auto/qml/linebylinelex/tst_linebylinelex.cpp
@@ -13,7 +13,7 @@ QT_USE_NAMESPACE
using namespace Qt::StringLiterals;
using namespace QQmlJS;
-class TestLineByLineLex : public QQmlDataTest
+class TestLineByLineLex : public QObject
{
Q_OBJECT
@@ -21,7 +21,7 @@ public:
TestLineByLineLex();
private Q_SLOTS:
- void initTestCase() override;
+ void initTestCase();
void testLineByLineLex_data();
void testLineByLineLex();
@@ -34,17 +34,14 @@ private:
QString m_qmljsrootgenPath;
QString m_qmltyperegistrarPath;
- QString m_baseDir;
};
TestLineByLineLex::TestLineByLineLex()
- : QQmlDataTest(QT_QMLTEST_DATADIR), m_baseDir(QString::fromLocal8Bit(QT_QMLTEST_DATADIR))
{
}
void TestLineByLineLex::initTestCase()
{
- QQmlDataTest::initTestCase();
}
void TestLineByLineLex::testLineByLineLex_data()
@@ -59,22 +56,18 @@ void TestLineByLineLex::testLineByLineLex()
{
QFETCH(QString, filename);
- QString filePath = m_baseDir + u"/linebylinelex/data/"_s + filename;
+ QString filePath = QFINDTESTDATA("data/" + filename);
runLex(filePath);
}
void TestLineByLineLex::testFormatter_data()
{
QTest::addColumn<QString>("filename");
- QDir formatData(m_baseDir + u"/qmlformat/data"_s);
- bool hasTestData = false; // ### TODO: fix test to always have data
+ QDir formatData(QFINDTESTDATA("qmlformat/data"));
for (const QFileInfo &fInfo :
formatData.entryInfoList(QStringList({ u"*.qml"_s, u"*.js"_s }), QDir::Files)) {
QTest::newRow(qPrintable(fInfo.fileName())) << fInfo.absoluteFilePath();
- hasTestData = true;
}
- if (!hasTestData)
- QSKIP("No test data found!");
}
void TestLineByLineLex::testFormatter()
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index daa16eba72..7bf3b34f86 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -5948,7 +5948,7 @@ void tst_QJSEngine::functionCtorGeneratedCUIsNotCollectedByGc()
const QString program = "new Function('a', 'b', 'let x = \"Hello\"; return a + b');";
auto sumFunc = engine.evaluate(program);
QVERIFY(sumFunc.isCallable());
- auto *function = QJSValuePrivate::asManagedType<QV4::FunctionObject>(&sumFunc);
+ auto *function = QJSValuePrivate::asManagedType<QV4::JavaScriptFunctionObject>(&sumFunc);
auto *cu = function->d()->function->executableCompilationUnit();
QVERIFY(cu->runtimeStrings); // should exist for "Hello"
QVERIFY(cu->runtimeStrings[0]->isMarked());
diff --git a/tests/auto/qml/qmlcachegen/CMakeLists.txt b/tests/auto/qml/qmlcachegen/CMakeLists.txt
index 2dacff35b5..d88de460e9 100644
--- a/tests/auto/qml/qmlcachegen/CMakeLists.txt
+++ b/tests/auto/qml/qmlcachegen/CMakeLists.txt
@@ -28,6 +28,7 @@ qt_internal_add_test(tst_qmlcachegen
Qt::Gui
Qt::QmlPrivate
Qt::QuickTestUtilsPrivate
+ Qt::QmlCompilerPrivate
TESTDATA ${test_data}
)
diff --git a/tests/auto/qml/qmlcachegen/data/aotstats/AotstatsClean.qml b/tests/auto/qml/qmlcachegen/data/aotstats/AotstatsClean.qml
new file mode 100644
index 0000000000..b48004dc87
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/data/aotstats/AotstatsClean.qml
@@ -0,0 +1,11 @@
+import QtQml
+
+QtObject {
+ property int i: 100
+ property int j: i * 2
+
+ function s() : string {
+ let s = "abc"
+ return s + "def "
+ }
+}
diff --git a/tests/auto/qml/qmlcachegen/data/aotstats/AotstatsMixed.qml b/tests/auto/qml/qmlcachegen/data/aotstats/AotstatsMixed.qml
new file mode 100644
index 0000000000..3d96760e96
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/data/aotstats/AotstatsMixed.qml
@@ -0,0 +1,7 @@
+import QtQml
+
+QtObject {
+ property int i: Math.max(1, 2) // OK
+ function f() { return 1 } // Error: No specified return type
+ property string s: g() // Error: g?
+}
diff --git a/tests/auto/qml/qmlcachegen/data/aotstats/cachegentest.qrc b/tests/auto/qml/qmlcachegen/data/aotstats/cachegentest.qrc
new file mode 100644
index 0000000000..4f156ad2ef
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/data/aotstats/cachegentest.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/cachegentest">
+ <file alias="qmldir">qmldir</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/qml/qmlcachegen/data/aotstats/qmldir b/tests/auto/qml/qmlcachegen/data/aotstats/qmldir
new file mode 100644
index 0000000000..72047cc99d
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/data/aotstats/qmldir
@@ -0,0 +1,3 @@
+module cachegentest
+AotstatsClean 254.0 AotstatsClean.qml
+AotstatsMixed 254.0 AotstatsMixed.qml
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
index 17a914c1dd..34ad3bbc98 100644
--- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -3,6 +3,7 @@
#include <qtest.h>
+#include <QJsonDocument>
#include <QQmlComponent>
#include <QQmlEngine>
#include <QProcess>
@@ -11,6 +12,7 @@
#include <QSysInfo>
#include <QLoggingCategory>
#include <private/qqmlcomponent_p.h>
+#include <private/qqmljscompilerstats_p.h>
#include <private/qqmlscriptdata_p.h>
#include <private/qv4compileddata_p.h>
#include <qtranslator.h>
@@ -67,6 +69,10 @@ private slots:
void scriptStringCachegenInteraction();
void saveableUnitPointer();
+
+ void aotstatsSerialization();
+ void aotstatsGeneration_data();
+ void aotstatsGeneration();
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
@@ -895,6 +901,133 @@ void tst_qmlcachegen::saveableUnitPointer()
QCOMPARE(unit.flags, flags);
}
+void tst_qmlcachegen::aotstatsSerialization()
+{
+ const auto createEntry = [](const auto &d, const auto &n, const auto &e, const auto &l,
+ const auto &c, const auto &s) -> QQmlJS::AotStatsEntry {
+ QQmlJS::AotStatsEntry entry;
+ entry.codegenDuration = d;
+ entry.functionName = n;
+ entry.errorMessage = e;
+ entry.line = l;
+ entry.column = c;
+ entry.codegenSuccessful = s;
+ return entry;
+ };
+
+ const auto equal = [](const auto &e1, const auto &e2) -> bool {
+ return e1.codegenDuration == e2.codegenDuration && e1.functionName == e2.functionName
+ && e1.errorMessage == e2.errorMessage && e1.line == e2.line
+ && e1.column == e2.column && e1.codegenSuccessful == e2.codegenSuccessful;
+ };
+
+ // AotStats
+ // +-ModuleA
+ // | +-File1
+ // | | +-e1
+ // | | +-e2
+ // | +-File2
+ // | | +-e3
+ // +-ModuleB
+ // | +-File3
+ // | | +-e4
+
+ QQmlJS::AotStats original;
+ QQmlJS::AotStatsEntry e1 = createEntry(std::chrono::microseconds(500), "f1", "", 1, 1, true);
+ QQmlJS::AotStatsEntry e2 = createEntry(std::chrono::microseconds(200), "f2", "err1", 5, 4, false);
+ QQmlJS::AotStatsEntry e3 = createEntry(std::chrono::microseconds(750), "f3", "", 20, 4, true);
+ QQmlJS::AotStatsEntry e4 = createEntry(std::chrono::microseconds(300), "f4", "err2", 5, 8, false);
+ original.addEntry("ModuleA", "File1", e1);
+ original.addEntry("ModuleA", "File1", e2);
+ original.addEntry("ModuleA", "File2", e3);
+ original.addEntry("ModuleB", "File3", e4);
+
+ const auto parsed = QQmlJS::AotStats::fromJsonDocument(original.toJsonDocument());
+ QCOMPARE(parsed.entries().size(), original.entries().size());
+
+ const auto &parsedA = parsed.entries()["ModuleA"];
+ const auto &originalA = original.entries()["ModuleA"];
+ QCOMPARE(parsedA.size(), originalA.size());
+ QCOMPARE(parsedA["File1"].size(), originalA["File1"].size());
+ QVERIFY(equal(parsedA["File1"][0], originalA["File1"][0]));
+ QVERIFY(equal(parsedA["File1"][1], originalA["File1"][1]));
+ QCOMPARE(parsedA["File2"].size(), originalA["File2"].size());
+ QVERIFY(equal(parsedA["File2"][0], originalA["File2"][0]));
+
+ const auto &parsedB = parsed.entries()["ModuleB"];
+ const auto &originalB = original.entries()["ModuleB"];
+ QCOMPARE(parsedB.size(), originalB.size());
+ QCOMPARE(parsedB["File3"].size(), originalB["File3"].size());
+ QVERIFY(equal(parsedB["File3"][0], originalB["File3"][0]));
+}
+
+struct FunctionEntry
+{
+ QString name;
+ QString errorMessage;
+ bool codegenSuccessful;
+};
+
+void tst_qmlcachegen::aotstatsGeneration_data()
+{
+ QTest::addColumn<QString>("qmlFile");
+ QTest::addColumn<QList<FunctionEntry>>("entries");
+
+ QTest::addRow("clean") << "AotstatsClean.qml"
+ << QList<FunctionEntry>{ { "j", "", true }, { "s", "", true } };
+
+ const QString fError = "function without return type annotation returns int. This may prevent "
+ "proper compilation to Cpp.";
+ const QString sError = "method g cannot be resolved.";
+ QTest::addRow("mixed") << "AotstatsMixed.qml"
+ << QList<FunctionEntry>{ { "i", "", true },
+ { "f", fError, false },
+ { "s", sError, false } };
+}
+
+void tst_qmlcachegen::aotstatsGeneration()
+{
+#if defined(QTEST_CROSS_COMPILED)
+ QSKIP("Cannot call qmlcachegen on cross-compiled target.");
+#endif
+ QFETCH(QString, qmlFile);
+ QFETCH(QList<FunctionEntry>, entries);
+
+ QTemporaryDir dir;
+ QProcess proc;
+ proc.setProgram(QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath) + "/qmlcachegen"_L1);
+ const QString cppOutput = dir.filePath(qmlFile + ".cpp");
+ const QString aotstatsOutput = cppOutput + ".aotstats";
+ proc.setArguments({ "--bare",
+ "--resource-path", "/cachegentest/data/aotstats/" + qmlFile,
+ "-i", testFile("aotstats/qmldir"),
+ "--resource", testFile("aotstats/cachegentest.qrc"),
+ "--dump-aot-stats",
+ "--module-id=Aotstats",
+ "-o", cppOutput,
+ testFile("aotstats/" + qmlFile) });
+ proc.start();
+ QVERIFY(proc.waitForFinished() && proc.exitStatus() == QProcess::NormalExit);
+
+ QVERIFY(QFileInfo::exists(aotstatsOutput));
+ QFile aotstatsFile(aotstatsOutput);
+ QVERIFY(aotstatsFile.open(QIODevice::Text | QIODevice::ReadOnly));
+ const auto document = QJsonDocument::fromJson(aotstatsFile.readAll());
+ const auto aotstats = QQmlJS::AotStats::fromJsonDocument(document);
+ QVERIFY(aotstats.entries().size() == 1); // One module
+ const auto &moduleEntries = aotstats.entries()["Aotstats"];
+ QVERIFY(moduleEntries.size() == 1); // Only one qml file was compiled
+ const auto &fileEntries = moduleEntries[moduleEntries.keys().first()];
+
+ for (const auto &entry : entries) {
+ const auto it = std::find_if(fileEntries.cbegin(), fileEntries.cend(),
+ [&](const auto &e) { return e.functionName == entry.name; });
+ QVERIFY(it != fileEntries.cend());
+ QVERIFY(it->codegenSuccessful == entry.codegenSuccessful);
+ QVERIFY(it->errorMessage == entry.errorMessage);
+ }
+}
+
const QQmlScriptString &ScriptStringProps::undef() const
{
return m_undef;
diff --git a/tests/auto/qml/qmlcppcodegen/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/CMakeLists.txt
index 42ad6d23d6..715ad6162a 100644
--- a/tests/auto/qml/qmlcppcodegen/CMakeLists.txt
+++ b/tests/auto/qml/qmlcppcodegen/CMakeLists.txt
@@ -19,6 +19,8 @@ qt_internal_add_test(tst_qmlcppcodegen
codegen_test_moduleplugin
codegen_test_hidden
codegen_test_hiddenplugin
+ codegen_test_stringbuilder
+ codegen_test_stringbuilderplugin
)
qt_internal_add_test(tst_qmlcppcodegen_interpreted
@@ -31,6 +33,8 @@ qt_internal_add_test(tst_qmlcppcodegen_interpreted
codegen_test_moduleplugin
codegen_test_hidden
codegen_test_hiddenplugin
+ codegen_test_stringbuilder
+ codegen_test_stringbuilderplugin
DEFINES
QT_TEST_FORCE_INTERPRETER
)
diff --git a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
index 8c5449d192..7f2e6ad967 100644
--- a/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
+++ b/tests/auto/qml/qmlcppcodegen/data/CMakeLists.txt
@@ -346,6 +346,33 @@ add_dependencies(codegen_test_hidden Qt::Quick)
qt_autogen_tools_initial_setup(codegen_test_hiddenplugin)
+qt_policy(SET QTP0004 NEW)
+
+qt_add_library(codegen_test_stringbuilder STATIC)
+qt_autogen_tools_initial_setup(codegen_test_stringbuilder)
+
+set_target_properties(codegen_test_stringbuilder PROPERTIES
+ # We really want qmlcachegen here, even if qmlsc is available
+ QT_QMLCACHEGEN_EXECUTABLE qmlcachegen
+ QT_QMLCACHEGEN_ARGUMENTS --validate-basic-blocks
+)
+
+target_compile_definitions(codegen_test_stringbuilder PRIVATE
+ -DGENERATED_CPP_FOLDER="${CMAKE_CURRENT_BINARY_DIR}/.rcc/qmlcache"
+ QT_USE_QSTRINGBUILDER
+)
+
+qt6_add_qml_module(codegen_test_stringbuilder
+ URI StringBuilderTestTypes
+ SOURCES
+ writableVariantMap.h
+ QML_FILES
+ writeVariantMap.qml
+ OUTPUT_DIRECTORY stringbuilderTestTypes
+ __QT_INTERNAL_DISAMBIGUATE_QMLDIR_RESOURCE
+)
+
+qt_autogen_tools_initial_setup(codegen_test_stringbuilderplugin)
qt_add_library(codegen_test_module STATIC)
qt_autogen_tools_initial_setup(codegen_test_module)
@@ -356,7 +383,7 @@ set_target_properties(codegen_test_module PROPERTIES
QT_QMLCACHEGEN_ARGUMENTS --validate-basic-blocks
)
-qt_policy(SET QTP0004 NEW)
+
target_compile_definitions(codegen_test_module PUBLIC
-DGENERATED_CPP_FOLDER="${CMAKE_CURRENT_BINARY_DIR}/.rcc/qmlcache"
diff --git a/tests/auto/qml/qmlcppcodegen/data/writableVariantMap.h b/tests/auto/qml/qmlcppcodegen/data/writableVariantMap.h
new file mode 100644
index 0000000000..3c0fedd28b
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/writableVariantMap.h
@@ -0,0 +1,31 @@
+#pragma once
+#include <QObject>
+#include <QVariantMap>
+#include <QtQml/qqmlregistration.h>
+
+class WritableVariantMap : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ Q_PROPERTY(QVariantMap data READ data WRITE setData NOTIFY dataChanged)
+
+public:
+ WritableVariantMap(QObject *parent = nullptr) : QObject(parent) { }
+
+ QVariantMap data() const { return m_data; }
+ void setData(const QVariantMap &data)
+ {
+ if (m_data != data) {
+ m_data = data;
+ emit dataChanged();
+ }
+ }
+
+signals:
+ void dataChanged();
+
+private:
+ QVariantMap m_data;
+};
+
+
diff --git a/tests/auto/qml/qmlcppcodegen/data/writeVariantMap.qml b/tests/auto/qml/qmlcppcodegen/data/writeVariantMap.qml
new file mode 100644
index 0000000000..536e53b408
--- /dev/null
+++ b/tests/auto/qml/qmlcppcodegen/data/writeVariantMap.qml
@@ -0,0 +1,10 @@
+pragma Strict
+import StringBuilderTestTypes
+
+WritableVariantMap {
+ id: dragSource
+ property string modelData: "Drag Me"
+ data: ({
+ "text/plain": "%" + dragSource.modelData + "%"
+ })
+}
diff --git a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
index 9b66143f62..53cc068e8c 100644
--- a/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
+++ b/tests/auto/qml/qmlcppcodegen/tst_qmlcppcodegen.cpp
@@ -256,6 +256,7 @@ private slots:
void voidConversion();
void voidFunction();
void writeBack();
+ void writeVariantMap();
};
static QByteArray arg1()
@@ -5107,6 +5108,22 @@ void tst_QmlCppCodegen::writeBack()
QCOMPARE(person->property("ints"), QVariant::fromValue(QList<int>({12, 22, 2, 1, 0, 0, 33})));
}
+void tst_QmlCppCodegen::writeVariantMap()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, QUrl(u"qrc:/qt/qml/StringBuilderTestTypes/writeVariantMap.qml"_s));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ const QVariantMap v = object->property("data").toMap();
+ QCOMPARE(v.size(), 1);
+ const QVariant textPlain = v[u"text/plain"_s];
+ QCOMPARE(textPlain.metaType(), QMetaType::fromType<QString>());
+ QCOMPARE(textPlain.toString(), u"%Drag Me%"_s);
+
+}
+
QTEST_MAIN(tst_QmlCppCodegen)
#include "tst_qmlcppcodegen.moc"
diff --git a/tests/auto/qml/qmlformat/data/enumWithValues.formatted.qml b/tests/auto/qml/qmlformat/data/enumWithValues.formatted.qml
new file mode 100644
index 0000000000..bbf978936f
--- /dev/null
+++ b/tests/auto/qml/qmlformat/data/enumWithValues.formatted.qml
@@ -0,0 +1,12 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Rectangle {
+ enum AxisAlignment {
+ Bottom = 0,
+ Left = 1,
+ Right = 2
+ }
+}
diff --git a/tests/auto/qml/qmlformat/data/enumWithValues.qml b/tests/auto/qml/qmlformat/data/enumWithValues.qml
new file mode 100644
index 0000000000..2dbe7fbac5
--- /dev/null
+++ b/tests/auto/qml/qmlformat/data/enumWithValues.qml
@@ -0,0 +1,12 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Rectangle{
+enum AxisAlignment{
+Bottom = 0,
+Left = 1,
+Right = 2
+}
+}
diff --git a/tests/auto/qml/qmlformat/tst_qmlformat.cpp b/tests/auto/qml/qmlformat/tst_qmlformat.cpp
index da3ebc69a2..11d4c9d2c7 100644
--- a/tests/auto/qml/qmlformat/tst_qmlformat.cpp
+++ b/tests/auto/qml/qmlformat/tst_qmlformat.cpp
@@ -390,7 +390,9 @@ void TestQmlformat::testFormat_data()
QTest::newRow("javascriptBlock")
<< "javascriptBlock.qml"
<< "javascriptBlock.formatted.qml" << QStringList{} << RunOption::OnCopy;
-
+ QTest::newRow("enumWithValues")
+ << "enumWithValues.qml"
+ << "enumWithValues.formatted.qml" << QStringList{} << RunOption::OnCopy;
//plainJS
QTest::newRow("nestedLambdaWithIfElse")
<< "lambdaWithIfElseInsideLambda.js"
diff --git a/tests/auto/qml/qmlimportscanner/data/CompositeSingleton.json b/tests/auto/qml/qmlimportscanner/data/CompositeSingleton.json
index 028685f566..8860b629d1 100644
--- a/tests/auto/qml/qmlimportscanner/data/CompositeSingleton.json
+++ b/tests/auto/qml/qmlimportscanner/data/CompositeSingleton.json
@@ -10,29 +10,25 @@
"name": "QtQuick",
"plugin": "qtquick2plugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQuick/",
"relativePath": "QtQuick",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQuick/"
+ "type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -40,9 +36,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -50,12 +46,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/CompositeWithEnum.json b/tests/auto/qml/qmlimportscanner/data/CompositeWithEnum.json
index 77faf99e6c..085d0bf6d4 100644
--- a/tests/auto/qml/qmlimportscanner/data/CompositeWithEnum.json
+++ b/tests/auto/qml/qmlimportscanner/data/CompositeWithEnum.json
@@ -5,24 +5,20 @@
"type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -30,9 +26,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -40,12 +36,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/CompositeWithinSingleton.json b/tests/auto/qml/qmlimportscanner/data/CompositeWithinSingleton.json
index cf446c33bd..c0cad1e3a1 100644
--- a/tests/auto/qml/qmlimportscanner/data/CompositeWithinSingleton.json
+++ b/tests/auto/qml/qmlimportscanner/data/CompositeWithinSingleton.json
@@ -10,29 +10,25 @@
"name": "QtQuick",
"plugin": "qtquick2plugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQuick/",
"relativePath": "QtQuick",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQuick/"
+ "type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -40,9 +36,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -50,12 +46,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/Drawer.qml.json b/tests/auto/qml/qmlimportscanner/data/Drawer.qml.json
index 0a885f058e..3abcd58b1c 100644
--- a/tests/auto/qml/qmlimportscanner/data/Drawer.qml.json
+++ b/tests/auto/qml/qmlimportscanner/data/Drawer.qml.json
@@ -1,23 +1,19 @@
[
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -25,9 +21,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -35,12 +31,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/Imports.json b/tests/auto/qml/qmlimportscanner/data/Imports.json
index 20b9c524c4..ee6903b1da 100644
--- a/tests/auto/qml/qmlimportscanner/data/Imports.json
+++ b/tests/auto/qml/qmlimportscanner/data/Imports.json
@@ -10,29 +10,25 @@
"name": "QtQuick",
"plugin": "qtquick2plugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQuick/",
"relativePath": "QtQuick",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQuick/"
+ "type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -40,9 +36,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -50,12 +46,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/ListProperty.qml.json b/tests/auto/qml/qmlimportscanner/data/ListProperty.qml.json
index f07b7e8494..0e733b551f 100644
--- a/tests/auto/qml/qmlimportscanner/data/ListProperty.qml.json
+++ b/tests/auto/qml/qmlimportscanner/data/ListProperty.qml.json
@@ -1,39 +1,29 @@
[
{
"classname": "QtQuick2Plugin",
- "name": "QtQuick",
"linkTarget": "Qt6::qtquick2plugin",
+ "name": "QtQuick",
"plugin": "qtquick2plugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQuick/",
"relativePath": "QtQuick",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQuick/"
- },
- {
- "name": "Things",
- "plugin": "doesNotExistPlugin",
- "relativePath": "Things",
"type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -41,9 +31,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -51,12 +41,14 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
+ "type": "module"
},
{
- "name": "QML",
+ "name": "Things",
+ "plugin": "doesNotExistPlugin",
+ "relativePath": "Things",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/QTBUG-45916.js.json b/tests/auto/qml/qmlimportscanner/data/QTBUG-45916.js.json
index 3aa7bc8282..d0d427f595 100644
--- a/tests/auto/qml/qmlimportscanner/data/QTBUG-45916.js.json
+++ b/tests/auto/qml/qmlimportscanner/data/QTBUG-45916.js.json
@@ -5,29 +5,25 @@
"name": "QtQuick",
"plugin": "qtquick2plugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQuick/",
"relativePath": "QtQuick",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQuick/"
+ "type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -35,9 +31,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -45,12 +41,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/Simple.qml.json b/tests/auto/qml/qmlimportscanner/data/Simple.qml.json
index 3aa7bc8282..d0d427f595 100644
--- a/tests/auto/qml/qmlimportscanner/data/Simple.qml.json
+++ b/tests/auto/qml/qmlimportscanner/data/Simple.qml.json
@@ -5,29 +5,25 @@
"name": "QtQuick",
"plugin": "qtquick2plugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQuick/",
"relativePath": "QtQuick",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQuick/"
+ "type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -35,9 +31,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -45,12 +41,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/Singleton.json b/tests/auto/qml/qmlimportscanner/data/Singleton.json
index 90f0ff19ad..1813d01efe 100644
--- a/tests/auto/qml/qmlimportscanner/data/Singleton.json
+++ b/tests/auto/qml/qmlimportscanner/data/Singleton.json
@@ -10,29 +10,25 @@
"name": "QtQuick",
"plugin": "qtquick2plugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQuick/",
"relativePath": "QtQuick",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQuick/"
+ "type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -40,9 +36,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -50,12 +46,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/Things.json b/tests/auto/qml/qmlimportscanner/data/Things.json
index 7782dd7c5f..a6081c89d8 100644
--- a/tests/auto/qml/qmlimportscanner/data/Things.json
+++ b/tests/auto/qml/qmlimportscanner/data/Things.json
@@ -11,29 +11,25 @@
"name": "QtQuick",
"plugin": "qtquick2plugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQuick/",
"relativePath": "QtQuick",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQuick/"
+ "type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -41,9 +37,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -51,12 +47,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/javascriptMethods.qml.json b/tests/auto/qml/qmlimportscanner/data/javascriptMethods.qml.json
index 8fe2da0078..7094d1c8e3 100644
--- a/tests/auto/qml/qmlimportscanner/data/javascriptMethods.qml.json
+++ b/tests/auto/qml/qmlimportscanner/data/javascriptMethods.qml.json
@@ -1,27 +1,19 @@
[
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
- "name": "QtQml",
- "plugin": "qmlmetaplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
- },
- {
"classname": "QtQmlPlugin",
"linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
+ "name": "QtQml",
"plugin": "qmlplugin",
"pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "prefer": ":/qt-project.org/imports/QtQml/",
+ "relativePath": "QtQml",
+ "type": "module"
},
{
- "name": "Methods.js",
- "type": "javascript"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -29,9 +21,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -39,12 +31,12 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
+ "type": "module"
},
{
- "name": "QML",
- "type": "module"
+ "name": "Methods.js",
+ "type": "javascript"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/localImport.qml.json b/tests/auto/qml/qmlimportscanner/data/localImport.qml.json
index 7782dd7c5f..a6081c89d8 100644
--- a/tests/auto/qml/qmlimportscanner/data/localImport.qml.json
+++ b/tests/auto/qml/qmlimportscanner/data/localImport.qml.json
@@ -11,29 +11,25 @@
"name": "QtQuick",
"plugin": "qtquick2plugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQuick/",
"relativePath": "QtQuick",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQuick/"
+ "type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -41,9 +37,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -51,12 +47,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/parentEnum.qml.json b/tests/auto/qml/qmlimportscanner/data/parentEnum.qml.json
index 3aa7bc8282..d0d427f595 100644
--- a/tests/auto/qml/qmlimportscanner/data/parentEnum.qml.json
+++ b/tests/auto/qml/qmlimportscanner/data/parentEnum.qml.json
@@ -5,29 +5,25 @@
"name": "QtQuick",
"plugin": "qtquick2plugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQuick/",
"relativePath": "QtQuick",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQuick/"
+ "type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -35,9 +31,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -45,12 +41,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/qmldirImportAndDepend.qml.json b/tests/auto/qml/qmlimportscanner/data/qmldirImportAndDepend.qml.json
index 7782dd7c5f..a6081c89d8 100644
--- a/tests/auto/qml/qmlimportscanner/data/qmldirImportAndDepend.qml.json
+++ b/tests/auto/qml/qmlimportscanner/data/qmldirImportAndDepend.qml.json
@@ -11,29 +11,25 @@
"name": "QtQuick",
"plugin": "qtquick2plugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQuick/",
"relativePath": "QtQuick",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQuick/"
+ "type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -41,9 +37,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -51,12 +47,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/qtQmlOnly.qml.json b/tests/auto/qml/qmlimportscanner/data/qtQmlOnly.qml.json
index 0a885f058e..3abcd58b1c 100644
--- a/tests/auto/qml/qmlimportscanner/data/qtQmlOnly.qml.json
+++ b/tests/auto/qml/qmlimportscanner/data/qtQmlOnly.qml.json
@@ -1,23 +1,19 @@
[
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -25,9 +21,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -35,12 +31,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmlimportscanner/data/rootPath.json b/tests/auto/qml/qmlimportscanner/data/rootPath.json
index b468a8acb1..41ce0f9a45 100644
--- a/tests/auto/qml/qmlimportscanner/data/rootPath.json
+++ b/tests/auto/qml/qmlimportscanner/data/rootPath.json
@@ -5,29 +5,25 @@
"name": "QtQuick",
"plugin": "qtquick2plugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQuick/",
"relativePath": "QtQuick",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQuick/"
+ "type": "module"
},
{
- "classname": "QtQmlMetaPlugin",
- "linkTarget": "Qt6::QmlMeta",
+ "classname": "QtQmlPlugin",
+ "linkTarget": "Qt6::qmlplugin",
"name": "QtQml",
- "plugin": "qmlmetaplugin",
+ "plugin": "qmlplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/",
"relativePath": "QtQml",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/"
+ "type": "module"
},
{
- "classname": "QtQmlPlugin",
- "linkTarget": "Qt6::qmlplugin",
- "name": "QtQml.Base",
- "plugin": "qmlplugin",
- "pluginIsOptional": true,
- "relativePath": "QtQml/Base",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Base/"
+ "name": "QML",
+ "prefer": ":/qt-project.org/imports/QML/",
+ "relativePath": "QML",
+ "type": "module"
},
{
"classname": "QtQmlModelsPlugin",
@@ -35,9 +31,9 @@
"name": "QtQml.Models",
"plugin": "modelsplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/Models/",
"relativePath": "QtQml/Models",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/Models/"
+ "type": "module"
},
{
"classname": "QtQmlWorkerScriptPlugin",
@@ -45,12 +41,8 @@
"name": "QtQml.WorkerScript",
"plugin": "workerscriptplugin",
"pluginIsOptional": true,
+ "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/",
"relativePath": "QtQml/WorkerScript",
- "type": "module",
- "prefer": ":/qt-project.org/imports/QtQml/WorkerScript/"
- },
- {
- "name": "QML",
"type": "module"
},
{
@@ -72,12 +64,12 @@
"type": "module"
},
{
- "name": "Imports",
- "relativePath": "Imports",
+ "name": "Module",
"type": "module"
},
{
- "name": "Module",
+ "name": "Imports",
+ "relativePath": "Imports",
"type": "module"
}
]
diff --git a/tests/auto/qml/qmllint/data/Qtbug111015/qtbug111015.qmltypes b/tests/auto/qml/qmllint/data/Qtbug111015/qtbug111015.qmltypes
index cad6d88cc3..7de521a379 100644
--- a/tests/auto/qml/qmllint/data/Qtbug111015/qtbug111015.qmltypes
+++ b/tests/auto/qml/qmllint/data/Qtbug111015/qtbug111015.qmltypes
@@ -9,4 +9,12 @@ Module {
prototype: "QObject"
Property { name: "jsonObjectList"; type: "QJsonObject"; isList: true; read: "getJsonObjectList"; index: 0; isReadonly: true }
}
+ Component {
+ file: "typewithjsonarray.h"
+ name: "TypeWithJsonArray"
+ exports: ["QmlLintTestLib/TypeWithJsonArray 1.0"]
+ accessSemantics: "reference"
+ prototype: "QObject"
+ Property { name: "jsonArray"; type: "QJsonArray"; read: "getJsonArray"; index: 0; isReadonly: true }
+ }
}
diff --git a/tests/auto/qml/qmllint/data/Things/plugins.qmltypes b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
index 47ae34cc00..3b0da602ac 100644
--- a/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
+++ b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes
@@ -112,6 +112,6 @@ Module {
prototype: "QObject"
exports: ["Things/ConstInvokable 1.0"]
exportMetaObjectRevisions: [256]
- Method { name: "getObject"; type: "QObject"; isPointer: true; isConstant: true }
+ Method { name: "getObject"; type: "QObject"; isPointer: true; isTypeConstant: true }
}
}
diff --git a/tests/auto/qml/qmllint/data/functionAssign1.qml b/tests/auto/qml/qmllint/data/functionAssign1.qml
new file mode 100644
index 0000000000..9a121a26b4
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/functionAssign1.qml
@@ -0,0 +1,6 @@
+import QtQml
+QtObject {
+ onObjectNameChanged: () => {
+ console.log("Entered")
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/functionAssign2.qml b/tests/auto/qml/qmllint/data/functionAssign2.qml
new file mode 100644
index 0000000000..ab3f94d990
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/functionAssign2.qml
@@ -0,0 +1,7 @@
+import QtQml
+QtObject {
+ onObjectNameChanged: function() {
+ console.log("Entered")
+ }
+}
+
diff --git a/tests/auto/qml/qmllint/data/jsonArrayIsRecognized.qml b/tests/auto/qml/qmllint/data/jsonArrayIsRecognized.qml
new file mode 100644
index 0000000000..89c52e0e52
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/jsonArrayIsRecognized.qml
@@ -0,0 +1,8 @@
+import QtQuick
+import Qtbug111015 1.0
+
+Item {
+ TypeWithJsonArray {
+ jsonArray: []
+ }
+}
diff --git a/tests/auto/qml/qmllint/data/something.qml b/tests/auto/qml/qmllint/data/something.qml
new file mode 100644
index 0000000000..38998f606d
--- /dev/null
+++ b/tests/auto/qml/qmllint/data/something.qml
@@ -0,0 +1,2 @@
+import ModuleInImportPath
+A {}
diff --git a/tests/auto/qml/qmllint/data/valueTypesFromString.qml b/tests/auto/qml/qmllint/data/valueTypesFromString.qml
index fc013f858f..1ae0a23681 100644
--- a/tests/auto/qml/qmllint/data/valueTypesFromString.qml
+++ b/tests/auto/qml/qmllint/data/valueTypesFromString.qml
@@ -2,6 +2,11 @@ import QtQuick
Item {
property point p: "30,50"
- property rect p3: "10, 20, 30x50"
property size p4: "30x50"
+ property rect p3: "10, 20, 30x50"
+ property vector2d p5: "1,2"
+ property vector3d p6: "1,2,3"
+ property vector4d p7: "1,2,3,4"
+ property quaternion p2: "1,2,3,4"
+ property matrix4x4 p8: "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16"
}
diff --git a/tests/auto/qml/qmllint/lintplugin.cpp b/tests/auto/qml/qmllint/lintplugin.cpp
index 65795c103c..58b174cb6b 100644
--- a/tests/auto/qml/qmllint/lintplugin.cpp
+++ b/tests/auto/qml/qmllint/lintplugin.cpp
@@ -23,7 +23,7 @@ public:
void run(const QQmlSA::Element &element) override
{
auto property = element.property(u"radius"_s);
- if (!property.isValid() || element.property(u"radius"_s).typeName() != u"qreal") {
+ if (!property.isValid() || element.property(u"radius"_s).typeName() != u"double") {
emitWarning(u"Failed to verify radius property", plugin, element.sourceLocation());
return;
}
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index a9b5f8d732..6925fc4f81 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -105,14 +105,18 @@ private Q_SLOTS:
void valueTypesFromString();
void ignoreSettingsNotCommandLineOptions();
+ void backslashedQmldirPath();
void environment_data();
void environment();
+ void maxWarnings();
+
#if QT_CONFIG(library)
void testPlugin();
void quickPlugin();
#endif
+
private:
enum DefaultImportOption { NoDefaultImports, UseDefaultImports };
enum ContainOption { StringNotContained, StringContained };
@@ -123,6 +127,11 @@ private:
enum LintType { LintFile, LintModule };
+ static QStringList warningsShouldFailArgs() {
+ static QStringList args {"-W", "0"};
+ return args;
+ }
+
QString runQmllint(const QString &fileToLint, std::function<void(QProcess &)> handleResult,
const QStringList &extraArgs = QStringList(), bool ignoreSettings = true,
bool addImportDirs = true, bool absolutePath = true,
@@ -409,7 +418,7 @@ void TestQmllint::autoqmltypes()
{
QProcess process;
process.setWorkingDirectory(testFile("autoqmltypes"));
- process.start(m_qmllintPath, { QStringLiteral("test.qml") });
+ process.start(m_qmllintPath, warningsShouldFailArgs() << QStringLiteral("test.qml") );
process.waitForFinished();
@@ -423,7 +432,7 @@ void TestQmllint::autoqmltypes()
{
QProcess bare;
bare.setWorkingDirectory(testFile("autoqmltypes"));
- bare.start(m_qmllintPath, { QStringLiteral("--bare"), QStringLiteral("test.qml") });
+ bare.start(m_qmllintPath, warningsShouldFailArgs() << QStringLiteral("--bare") << QStringLiteral("test.qml") );
bare.waitForFinished();
const QByteArray errors = bare.readAllStandardError();
@@ -760,7 +769,8 @@ void TestQmllint::dirtyQmlCode_data()
QTest::newRow("badAttachedProperty")
<< QStringLiteral("badAttachedProperty.qml")
<< Result { { Message {
- QStringLiteral("Member \"progress\" not found on type \"TestType\"") } } };
+ QStringLiteral("Member \"progress\" not found on type \"TestTypeAttached\"")
+ } } };
QTest::newRow("badAttachedPropertyNested")
<< QStringLiteral("badAttachedPropertyNested.qml")
<< Result { { Message { QStringLiteral(
@@ -1026,7 +1036,7 @@ expression: \${expr} \${expr} \\\${expr} \\\${expr}`)",
{ Message { QStringLiteral("Ready") } } } };
QTest::newRow("nullBinding") << QStringLiteral("nullBinding.qml")
<< Result{ { Message{ QStringLiteral(
- "Cannot assign literal of type null to qreal") } } };
+ "Cannot assign literal of type null to double") } } };
QTest::newRow("missingRequiredAlias")
<< QStringLiteral("missingRequiredAlias.qml")
<< Result { { Message {
@@ -1346,6 +1356,7 @@ void TestQmllint::cleanQmlCode_data()
QTest::newRow("constInvokable") << QStringLiteral("useConstInvokable.qml");
QTest::newRow("dontCheckJSTypes") << QStringLiteral("dontCheckJSTypes.qml");
QTest::newRow("jsonObjectIsRecognized") << QStringLiteral("jsonObjectIsRecognized.qml");
+ QTest::newRow("jsonArrayIsRecognized") << QStringLiteral("jsonArrayIsRecognized.qml");
}
void TestQmllint::cleanQmlCode()
@@ -1371,8 +1382,7 @@ void TestQmllint::compilerWarnings_data()
QTest::newRow("shadowable")
<< QStringLiteral("shadowable.qml")
- << Result { { Message {QStringLiteral(
- "with type NotSoSimple (stored as QQuickItem) can be shadowed") } } }
+ << Result { { Message {QStringLiteral("with type NotSoSimple can be shadowed") } } }
<< true;
QTest::newRow("tooFewParameters")
<< QStringLiteral("tooFewParams.qml")
@@ -1408,20 +1418,20 @@ void TestQmllint::compilerWarnings_data()
<< QStringLiteral("returnTypeAnnotation_component.qml")
<< Result{ { { "Could not compile function comp: function without return type "
"annotation returns (component in" },
- { "returnTypeAnnotation_component.qml)::c with type Comp (stored as "
- "QQuickItem). This may prevent proper compilation to Cpp." } } }
+ { "returnTypeAnnotation_component.qml)::c with type Comp. "
+ "This may prevent proper compilation to Cpp." } } }
<< true;
QTest::newRow("returnTypeAnnotation-enum")
<< QStringLiteral("returnTypeAnnotation_enum.qml")
<< Result{ { { "Could not compile function enumeration: function without return type "
- "annotation returns QQuickText::HAlignment::AlignRight (stored as int). "
+ "annotation returns QQuickText::HAlignment::AlignRight. "
"This may prevent proper compilation to Cpp." } } }
<< true;
QTest::newRow("returnTypeAnnotation-method")
<< QStringLiteral("returnTypeAnnotation_method.qml")
<< Result{ { { "Could not compile function method: function without return type "
"annotation returns (component in " }, // Don't check the build folder path
- { "returnTypeAnnotation_method.qml)::f(...) (stored as QJSValue). This may "
+ { "returnTypeAnnotation_method.qml)::f(...). This may "
"prevent proper compilation to Cpp." } } }
<< true;
QTest::newRow("returnTypeAnnotation-property")
@@ -1437,6 +1447,11 @@ void TestQmllint::compilerWarnings_data()
"annotation returns double. This may prevent proper compilation to "
"Cpp." } } }
<< true;
+
+ QTest::newRow("functionAssign1")
+ << QStringLiteral("functionAssign1.qml") << Result::clean() << true;
+ QTest::newRow("functionAssign2")
+ << QStringLiteral("functionAssign2.qml") << Result::clean() << true;
}
void TestQmllint::compilerWarnings()
@@ -1793,17 +1808,17 @@ void TestQmllint::requiredProperty()
void TestQmllint::settingsFile()
{
- QVERIFY(runQmllint("settings/unqualifiedSilent/unqualified.qml", true, QStringList(), false)
+ QVERIFY(runQmllint("settings/unqualifiedSilent/unqualified.qml", true, warningsShouldFailArgs(), false)
.isEmpty());
- QVERIFY(runQmllint("settings/unusedImportWarning/unused.qml", false, QStringList(), false)
+ QVERIFY(runQmllint("settings/unusedImportWarning/unused.qml", false, warningsShouldFailArgs(), false)
.contains(QStringLiteral("Warning: %1:2:1: Unused import")
.arg(testFile("settings/unusedImportWarning/unused.qml"))));
- QVERIFY(runQmllint("settings/bare/bare.qml", false, {}, false, false)
+ QVERIFY(runQmllint("settings/bare/bare.qml", false, warningsShouldFailArgs(), false, false)
.contains(QStringLiteral("Failed to find the following builtins: "
- "builtins.qmltypes, jsroot.qmltypes")));
- QVERIFY(runQmllint("settings/qmltypes/qmltypes.qml", false, QStringList(), false)
+ "jsroot.qmltypes, builtins.qmltypes")));
+ QVERIFY(runQmllint("settings/qmltypes/qmltypes.qml", false, warningsShouldFailArgs(), false)
.contains(QStringLiteral("not a qmldir file. Assuming qmltypes.")));
- QVERIFY(runQmllint("settings/qmlimports/qmlimports.qml", true, QStringList(), false).isEmpty());
+ QVERIFY(runQmllint("settings/qmlimports/qmlimports.qml", true, warningsShouldFailArgs(), false).isEmpty());
}
void TestQmllint::additionalImplicitImport()
@@ -1908,13 +1923,13 @@ void TestQmllint::missingBuiltinsNoCrash()
checkResult(warnings,
Result { { Message { QStringLiteral("Failed to find the following builtins: "
- "builtins.qmltypes, jsroot.qmltypes") } } });
+ "jsroot.qmltypes, builtins.qmltypes") } } });
}
void TestQmllint::absolutePath()
{
- QString absPathOutput = runQmllint("memberNotFound.qml", false, {}, true, true, true);
- QString relPathOutput = runQmllint("memberNotFound.qml", false, {}, true, true, false);
+ QString absPathOutput = runQmllint("memberNotFound.qml", false, warningsShouldFailArgs(), true, true, true);
+ QString relPathOutput = runQmllint("memberNotFound.qml", false, warningsShouldFailArgs(), true, true, false);
const QString absolutePath = QFileInfo(testFile("memberNotFound.qml")).absoluteFilePath();
QVERIFY(absPathOutput.contains(absolutePath));
@@ -2008,17 +2023,34 @@ void TestQmllint::valueTypesFromString()
runTest("valueTypesFromString.qml",
Result{ {
Message{
+ u"Binding is not supported: Type QPointF should be constructed using QML_STRUCTURED_VALUE's construction mechanism, instead of a string."_s },
+ Message{
u"Binding is not supported: Type QSizeF should be constructed using QML_STRUCTURED_VALUE's construction mechanism, instead of a string."_s },
Message{
u"Binding is not supported: Type QRectF should be constructed using QML_STRUCTURED_VALUE's construction mechanism, instead of a string."_s },
Message{
- u"Binding is not supported: Type QPointF should be constructed using QML_STRUCTURED_VALUE's construction mechanism, instead of a string."_s },
+ u"Binding is not supported: Type QVector2D should be constructed using QML_STRUCTURED_VALUE's construction mechanism, instead of a string."_s },
+ Message{
+ u"Binding is not supported: Type QVector3D should be constructed using QML_STRUCTURED_VALUE's construction mechanism, instead of a string."_s },
+ Message{
+ u"Binding is not supported: Type QVector4D should be constructed using QML_STRUCTURED_VALUE's construction mechanism, instead of a string."_s },
+ Message{
+ u"Binding is not supported: Type QQuaternion should be constructed using QML_STRUCTURED_VALUE's construction mechanism, instead of a string."_s },
+ Message{
+ u"Binding is not supported: Type QMatrix4x4 should be constructed using QML_STRUCTURED_VALUE's construction mechanism, instead of a string."_s },
},
{ /*bad messages */ },
{
Message{ u"({ width: 30, height: 50 })"_s },
Message{ u"({ x: 10, y: 20, width: 30, height: 50 })"_s },
Message{ u"({ x: 30, y: 50 })"_s },
+ Message{ u"({ x: 1, y: 2 })"_s },
+ Message{ u"({ x: 1, y: 2 })"_s },
+ Message{ u"({ x: 1, y: 2, z: 3 })"_s },
+ Message{ u"({ x: 1, y: 2, z: 3, w: 4 })"_s },
+ Message{ u"({ scalar: 1, x: 2, y: 3, z: 4 })"_s },
+ Message{
+ u"({ m11: 1, m12: 2, m13: 3, m14: 4, m21: 5, m22: 6, m23: 7, m24: 8, m31: 9, m32: 10, m33: 11, m34: 12, m41: 13, m42: 14, m43: 15, m44: 16 })"_s },
} });
}
@@ -2121,7 +2153,7 @@ void TestQmllint::quickPlugin()
Message { u"SplitView attached property only works with Items"_s },
Message { u"ScrollIndicator must be attached to a Flickable"_s },
Message { u"ScrollBar must be attached to a Flickable or ScrollView"_s },
- Message { u"Accessible must be attached to an Item"_s },
+ Message { u"Accessible must be attached to an Item or an Action"_s },
Message { u"EnterKey attached property only works with Items"_s },
Message {
u"LayoutDirection attached property only works with Items and Windows"_s },
@@ -2206,7 +2238,7 @@ void TestQmllint::environment_data()
const QString noWarningExpected;
QTest::addRow("missing-import-dir")
- << fileThatNeedsImportPath << false << QStringList{}
+ << fileThatNeedsImportPath << false << warningsShouldFailArgs()
<< Environment{ { u"QML_IMPORT_PATH"_s, importPath } } << noWarningExpected;
QTest::addRow("import-dir-via-arg")
@@ -2240,6 +2272,18 @@ void TestQmllint::environment()
}
}
+void TestQmllint::maxWarnings()
+{
+ // warnings are not fatal by default
+ runQmllint(testFile("badScript.qml"), true);
+ // or when max-warnings is set to -1
+ runQmllint(testFile("badScript.qml"), true, {"-W", "-1"});
+ // 1 warning => should fail
+ runQmllint(testFile("badScript.qml"), false, {"--max-warnings", "0"});
+ // only 1 warning => should exit normally
+ runQmllint(testFile("badScript.qml"), true, {"--max-warnings", "1"});
+}
+
#endif
void TestQmllint::ignoreSettingsNotCommandLineOptions()
@@ -2253,5 +2297,14 @@ void TestQmllint::ignoreSettingsNotCommandLineOptions()
QCOMPARE(output, QString());
}
+void TestQmllint::backslashedQmldirPath()
+{
+ const QString qmldirPath
+ = testFile(u"ImportPath/ModuleInImportPath/qmldir"_s).replace('/', QDir::separator());
+ const QString output = runQmllint(
+ testFile(u"something.qml"_s), true, QStringList{ u"-i"_s, qmldirPath });
+ QVERIFY(output.isEmpty());
+}
+
QTEST_GUILESS_MAIN(TestQmllint)
#include "tst_qmllint.moc"
diff --git a/tests/auto/qml/qmltc_qprocess/tst_qmltc_qprocess.cpp b/tests/auto/qml/qmltc_qprocess/tst_qmltc_qprocess.cpp
index 31c27c3cd7..cdbd9695fd 100644
--- a/tests/auto/qml/qmltc_qprocess/tst_qmltc_qprocess.cpp
+++ b/tests/auto/qml/qmltc_qprocess/tst_qmltc_qprocess.cpp
@@ -153,7 +153,7 @@ void tst_qmltc_qprocess::noBuiltins()
QVERIFY(file.rename(original));
};
- for (QString builtin : { u"builtins.qmltypes"_s, u"jsroot.qmltypes"_s }) {
+ for (QString builtin : { u"jsroot.qmltypes"_s, u"builtins.qmltypes"_s }) {
const auto path = QLibraryInfo::path(QLibraryInfo::QmlImportsPath) + u"/"_s + builtin;
QScopeGuard scope(std::bind(renameBack, path));
diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp
index 822caea0d0..e79e9b84b6 100644
--- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp
+++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp
@@ -498,17 +498,17 @@ void tst_qmltyperegistrar::hasIsConstantInParameters()
QVERIFY(qmltypesData.contains(R"( Signal {
name: "mySignal"
Parameter { name: "myObject"; type: "QObject"; isPointer: true }
- Parameter { name: "myConstObject"; type: "QObject"; isPointer: true; isConstant: true }
- Parameter { name: "myConstObject2"; type: "QObject"; isPointer: true; isConstant: true }
+ Parameter { name: "myConstObject"; type: "QObject"; isPointer: true; isTypeConstant: true }
+ Parameter { name: "myConstObject2"; type: "QObject"; isPointer: true; isTypeConstant: true }
Parameter { name: "myObject2"; type: "QObject"; isPointer: true }
- Parameter { name: "myConstObject3"; type: "QObject"; isPointer: true; isConstant: true }
+ Parameter { name: "myConstObject3"; type: "QObject"; isPointer: true; isTypeConstant: true }
}
)"));
QVERIFY(qmltypesData.contains(R"(Signal {
name: "myVolatileSignal"
- Parameter { name: "a"; type: "volatile QObject"; isPointer: true; isConstant: true }
- Parameter { name: "b"; type: "volatile QObject"; isPointer: true; isConstant: true }
+ Parameter { name: "a"; type: "volatile QObject"; isPointer: true; isTypeConstant: true }
+ Parameter { name: "b"; type: "volatile QObject"; isPointer: true; isTypeConstant: true }
Parameter { name: "nonConst"; type: "volatile QObject"; isPointer: true }
}
)"));
@@ -682,7 +682,6 @@ void tst_qmltyperegistrar::constructibleValueType()
name: "Constructible"
accessSemantics: "value"
exports: ["QmlTypeRegistrarTest/constructible 1.0"]
- isCreatable: true
exportMetaObjectRevisions: [256]
Method {
name: "Constructible"
@@ -701,7 +700,6 @@ void tst_qmltyperegistrar::structuredValueType()
name: "Structured"
accessSemantics: "value"
exports: ["QmlTypeRegistrarTest/structured 1.0"]
- isCreatable: true
isStructured: true
exportMetaObjectRevisions: [256]
Property { name: "i"; type: "int"; index: 0; isFinal: true }
@@ -735,51 +733,50 @@ void tst_qmltyperegistrar::typedEnum()
accessSemantics: "reference"
prototype: "QObject"
exports: ["QmlTypeRegistrarTest/TypedEnum 1.0"]
- isCreatable: true
exportMetaObjectRevisions: [256]
Enum {
name: "UChar"
- type: "uchar"
+ type: "quint8"
values: ["V0"]
}
Enum {
name: "Int8_T"
- type: "int8_t"
+ type: "qint8"
values: ["V1"]
}
Enum {
name: "UInt8_T"
- type: "uint8_t"
+ type: "quint8"
values: ["V2"]
}
Enum {
name: "Int16_T"
- type: "int16_t"
+ type: "short"
values: ["V3"]
}
Enum {
name: "UInt16_T"
- type: "uint16_t"
+ type: "ushort"
values: ["V4"]
}
Enum {
name: "Int32_T"
- type: "int32_t"
+ type: "int"
values: ["V5"]
}
Enum {
name: "UInt32_T"
- type: "uint32_t"
+ type: "uint"
values: ["V6"]
}
Enum {
name: "S"
- type: "qint16"
+ type: "short"
values: ["A", "B", "C"]
}
Enum {
name: "T"
- type: "quint16"
+ type: "ushort"
values: ["D", "E", "F"]
}
Enum {
@@ -805,7 +802,7 @@ void tst_qmltyperegistrar::listSignal()
prototype: "QObject"
Signal {
name: "objectListHappened"
- Parameter { type: "QList<QObject*>" }
+ Parameter { type: "QObjectList" }
}
})"));
}
@@ -823,7 +820,7 @@ void tst_qmltyperegistrar::withNamespace()
read: "bar"
index: 0
isReadonly: true
- isConstant: true
+ isPropertyConstant: true
}
})"));
@@ -833,9 +830,15 @@ void tst_qmltyperegistrar::withNamespace()
accessSemantics: "reference"
prototype: "Testing::Foo"
exports: ["QmlTypeRegistrarTest/Bar 1.0"]
- isCreatable: true
exportMetaObjectRevisions: [256]
- Property { name: "barProp"; type: "int"; read: "bar"; index: 0; isReadonly: true; isConstant: true }
+ Property {
+ name: "barProp"
+ type: "int"
+ read: "bar"
+ index: 0
+ isReadonly: true
+ isPropertyConstant: true
+ }
})"));
QVERIFY(qmltypesData.contains(R"(Component {
@@ -843,7 +846,14 @@ void tst_qmltyperegistrar::withNamespace()
name: "Testing::Foo"
accessSemantics: "reference"
prototype: "QObject"
- Property { name: "fooProp"; type: "int"; read: "foo"; index: 0; isReadonly: true; isConstant: true }
+ Property {
+ name: "fooProp"
+ type: "int"
+ read: "foo"
+ index: 0
+ isReadonly: true
+ isPropertyConstant: true
+ }
})"));
QVERIFY(qmltypesData.contains(R"(Component {
@@ -853,7 +863,6 @@ void tst_qmltyperegistrar::withNamespace()
prototype: "Testing::Bar"
extension: "Bar"
exports: ["QmlTypeRegistrarTest/Baz 1.0"]
- isCreatable: true
exportMetaObjectRevisions: [256]
attachedType: "Testing::Foo"
})"));
@@ -937,7 +946,6 @@ void tst_qmltyperegistrar::nameExplosion()
"QmlTypeRegistrarTest/Name2 1.0",
"QmlTypeRegistrarTest/NameExplosion 1.0"
]
- isCreatable: true
exportMetaObjectRevisions: [256]
})"));
@@ -962,7 +970,6 @@ void tst_qmltyperegistrar::javaScriptExtension()
extension: "SymbolPrototype"
extensionIsJavaScript: true
exports: ["QmlTypeRegistrarTest/JavaScriptExtension 1.0"]
- isCreatable: true
exportMetaObjectRevisions: [256]
})"));
}
@@ -978,7 +985,6 @@ void tst_qmltyperegistrar::relatedAddedInVersion()
"QmlTypeRegistrarTest/AddedIn1_0 1.0",
"QmlTypeRegistrarTest/AddedIn1_0 1.5"
]
- isCreatable: true
exportMetaObjectRevisions: [256, 261]
})"));
}
@@ -991,12 +997,11 @@ void tst_qmltyperegistrar::longNumberTypes()
accessSemantics: "reference"
prototype: "QObject"
exports: ["QmlTypeRegistrarTest/LongNumberTypes 1.0"]
- isCreatable: true
exportMetaObjectRevisions: [256]
- Property { name: "a"; type: "qint64"; index: 0 }
- Property { name: "b"; type: "int64_t"; index: 1 }
- Property { name: "c"; type: "quint64"; index: 2 }
- Property { name: "d"; type: "uint64_t"; index: 3 }
+ Property { name: "a"; type: "qlonglong"; index: 0 }
+ Property { name: "b"; type: "qlonglong"; index: 1 }
+ Property { name: "c"; type: "qulonglong"; index: 2 }
+ Property { name: "d"; type: "qulonglong"; index: 3 }
})"));
}
@@ -1017,9 +1022,66 @@ void tst_qmltyperegistrar::constReturnType()
accessSemantics: "reference"
prototype: "QObject"
exports: ["QmlTypeRegistrarTest/ConstInvokable 1.0"]
- isCreatable: true
exportMetaObjectRevisions: [256]
- Method { name: "getObject"; type: "QObject"; isPointer: true; isConstant: true }
+ Method { name: "getObject"; type: "QObject"; isPointer: true; isTypeConstant: true }
+ })"));
+}
+
+void tst_qmltyperegistrar::usingDeclaration()
+{
+ QVERIFY(qmltypesData.contains(R"(Component {
+ file: "tst_qmltyperegistrar.h"
+ name: "WithMyInt"
+ accessSemantics: "reference"
+ prototype: "QObject"
+ exports: ["QmlTypeRegistrarTest/WithMyInt 1.0"]
+ exportMetaObjectRevisions: [256]
+ Property { name: "a"; type: "int"; read: "a"; index: 0; isReadonly: true; isPropertyConstant: true }
+ })"));
+}
+
+void tst_qmltyperegistrar::enumsRegistered()
+{
+ QCOMPARE(QMetaType::fromName("SizeEnums::Unit"), QMetaType::fromType<SizeEnums::Unit>());
+ QCOMPARE(QMetaType::fromName("Local::Flag"), QMetaType::fromType<Local::Flag>());
+ QCOMPARE(QMetaType::fromName("Local::Flags"), QMetaType::fromType<Local::Flags>());
+ QCOMPARE(QMetaType::fromName("ValueTypeWithEnum1::Quality"),
+ QMetaType::fromType<ValueTypeWithEnum1::Quality>());
+ QCOMPARE(QMetaType::fromName("ValueTypeWithEnum2::Quality"),
+ QMetaType::fromType<ValueTypeWithEnum2::Quality>());
+ QCOMPARE(QMetaType::fromName("BaseNamespace::BBB"), QMetaType::fromType<BaseNamespace::BBB>());
+ QCOMPARE(QMetaType::fromName("ExtensionValueType::EEE"),
+ QMetaType::fromType<ExtensionValueType::EEE>());
+ QCOMPARE(QMetaType::fromName("TypedEnum::UChar"), QMetaType::fromType<TypedEnum::UChar>());
+ QCOMPARE(QMetaType::fromName("TypedEnum::Int8_T"), QMetaType::fromType<TypedEnum::Int8_T>());
+ QCOMPARE(QMetaType::fromName("TypedEnum::UInt8_T"), QMetaType::fromType<TypedEnum::UInt8_T>());
+ QCOMPARE(QMetaType::fromName("TypedEnum::Int16_T"), QMetaType::fromType<TypedEnum::Int16_T>());
+ QCOMPARE(QMetaType::fromName("TypedEnum::UInt16_T"), QMetaType::fromType<TypedEnum::UInt16_T>());
+ QCOMPARE(QMetaType::fromName("TypedEnum::Int32_T"), QMetaType::fromType<TypedEnum::Int32_T>());
+ QCOMPARE(QMetaType::fromName("TypedEnum::UInt32_T"), QMetaType::fromType<TypedEnum::UInt32_T>());
+ QCOMPARE(QMetaType::fromName("TypedEnum::S"), QMetaType::fromType<TypedEnum::S>());
+ QCOMPARE(QMetaType::fromName("TypedEnum::T"), QMetaType::fromType<TypedEnum::T>());
+ QCOMPARE(QMetaType::fromName("TypedEnum::U"), QMetaType::fromType<TypedEnum::U>());
+ QCOMPARE(QMetaType::fromName("TypedEnum::V"), QMetaType::fromType<TypedEnum::V>());
+ QCOMPARE(QMetaType::fromName("NetworkManager::NM"), QMetaType::fromType<NetworkManager::NM>());
+ QCOMPARE(QMetaType::fromName("NotNamespace::Abc"), QMetaType::fromType<NotNamespace::Abc>());
+}
+
+void tst_qmltyperegistrar::doNotDuplicateQtNamespace()
+{
+ QVERIFY(!qmltypesData.contains(R"(file: "qnamespace.h")"));
+}
+
+void tst_qmltyperegistrar::slotsBeforeInvokables()
+{
+ QVERIFY(qmltypesData.contains(R"(Component {
+ file: "tst_qmltyperegistrar.h"
+ name: "SlotsBeforeInvokables"
+ accessSemantics: "reference"
+ prototype: "QObject"
+ Method { name: "bar" }
+ Method { name: "foo" }
+ Method { name: "baz" }
})"));
}
diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h
index 371fb840d1..1eff2af024 100644
--- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h
+++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h
@@ -17,6 +17,7 @@
#include <QtQml/qqmlcomponent.h>
#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qnamespace.h>
#include <QtCore/qproperty.h>
#include <QtCore/qrect.h>
#include <QtCore/qtemporaryfile.h>
@@ -792,6 +793,45 @@ public:
Q_INVOKABLE const QObject *getObject() { return nullptr; }
};
+using myint = int;
+
+struct IntAlias
+{
+ Q_GADGET
+ QML_FOREIGN(myint)
+ QML_USING(int);
+};
+
+class WithMyInt : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ Q_PROPERTY(myint a READ a CONSTANT)
+public:
+ myint a() const { return 10; }
+};
+
+class UsesQtNamespace : public QObject
+{
+ Q_OBJECT
+ QML_ANONYMOUS
+ Q_PROPERTY(Qt::Key key READ key CONSTANT)
+public:
+ Qt::Key key() const { return Qt::Key_Escape; }
+};
+
+class SlotsBeforeInvokables : public QObject
+{
+ Q_OBJECT
+ QML_ANONYMOUS
+public:
+ Q_INVOKABLE void foo() {}
+public Q_SLOTS:
+ void bar() {}
+public:
+ Q_INVOKABLE void baz() {}
+};
+
class tst_qmltyperegistrar : public QObject
{
Q_OBJECT
@@ -865,6 +905,11 @@ private slots:
void enumList();
void constReturnType();
+ void usingDeclaration();
+ void enumsRegistered();
+ void doNotDuplicateQtNamespace();
+ void slotsBeforeInvokables();
+
private:
QByteArray qmltypesData;
};
diff --git a/tests/auto/qml/qqmlapplicationengine/loadFromModuleTranslationsCppType/CMakeLists.txt b/tests/auto/qml/qqmlapplicationengine/loadFromModuleTranslationsCppType/CMakeLists.txt
index f6fa23e010..5c308b1f7e 100644
--- a/tests/auto/qml/qqmlapplicationengine/loadFromModuleTranslationsCppType/CMakeLists.txt
+++ b/tests/auto/qml/qqmlapplicationengine/loadFromModuleTranslationsCppType/CMakeLists.txt
@@ -1,7 +1,7 @@
# Copyright (C) 2024 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
-qt_standard_project_setup(REQUIRES 6.5 I18N_LANGUAGES es)
+qt_standard_project_setup(REQUIRES 6.5 I18N_TRANSLATED_LANGUAGES es)
qt_internal_add_executable(i18nLoadFromModuleCppType
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
diff --git a/tests/auto/qml/qqmlapplicationengine/loadFromModuleTranslationsQmlType/CMakeLists.txt b/tests/auto/qml/qqmlapplicationengine/loadFromModuleTranslationsQmlType/CMakeLists.txt
index 088648040d..66183bc9c8 100644
--- a/tests/auto/qml/qqmlapplicationengine/loadFromModuleTranslationsQmlType/CMakeLists.txt
+++ b/tests/auto/qml/qqmlapplicationengine/loadFromModuleTranslationsQmlType/CMakeLists.txt
@@ -1,7 +1,7 @@
# Copyright (C) 2024 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
-qt_standard_project_setup(REQUIRES 6.5 I18N_LANGUAGES fr)
+qt_standard_project_setup(REQUIRES 6.5 I18N_TRANSLATED_LANGUAGES fr)
qt_internal_add_executable(i18nLoadFromModuleQmlType
OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/"
diff --git a/tests/auto/qml/qqmlbinding/CMakeLists.txt b/tests/auto/qml/qqmlbinding/CMakeLists.txt
index 0419240921..0249bb0f25 100644
--- a/tests/auto/qml/qqmlbinding/CMakeLists.txt
+++ b/tests/auto/qml/qqmlbinding/CMakeLists.txt
@@ -28,6 +28,7 @@ qt_internal_add_test(tst_qqmlbinding
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
+ Qt::QmlMetaPrivate
Qt::QuickPrivate
Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
@@ -42,6 +43,7 @@ qt_internal_add_test(tst_qqmlbinding_no_deferred_properties
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
+ Qt::QmlMetaPrivate
Qt::QuickPrivate
Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
diff --git a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
index 494d765798..b13379a103 100644
--- a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
+++ b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp
@@ -1,13 +1,17 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-#include <qtest.h>
+
+#include "WithBindableProperties.h"
+
+#include <private/qmlutils_p.h>
+#include <private/qqmlbind_p.h>
+#include <private/qqmlcomponentattached_p.h>
+#include <private/qquickrectangle_p.h>
+
+#include <QtTest/qtest.h>
+
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
-#include <QtQml/private/qqmlbind_p.h>
-#include <QtQml/private/qqmlcomponentattached_p.h>
-#include <QtQuick/private/qquickrectangle_p.h>
-#include <QtQuickTestUtils/private/qmlutils_p.h>
-#include "WithBindableProperties.h"
class tst_qqmlbinding : public QQmlDataTest
{
diff --git a/tests/auto/qml/qqmlconnections/CMakeLists.txt b/tests/auto/qml/qqmlconnections/CMakeLists.txt
index dd1814fed1..0e6947370d 100644
--- a/tests/auto/qml/qqmlconnections/CMakeLists.txt
+++ b/tests/auto/qml/qqmlconnections/CMakeLists.txt
@@ -27,6 +27,7 @@ qt_internal_add_test(tst_qqmlconnections
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
+ Qt::QmlMetaPrivate
Qt::QuickPrivate
Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
diff --git a/tests/auto/qml/qqmlecmascript/data/lookupsDoNotBypassProxy.qml b/tests/auto/qml/qqmlecmascript/data/lookupsDoNotBypassProxy.qml
new file mode 100644
index 0000000000..321bd21ad8
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/lookupsDoNotBypassProxy.qml
@@ -0,0 +1,29 @@
+import QtQml
+
+QtObject {
+ function test_proxy() {
+ let base = {
+ id: 'baseid',
+ name: 'basename',
+ length: 42
+ };
+
+ let handler = {
+ get: function (ao, prop) {
+ return Reflect.get(ao, prop);
+ }
+ };
+
+ let r = new Proxy(base, handler);
+ let validCount = 0;
+ if (r.id === base.id)
+ ++validCount;
+ if (r.length === base.length)
+ ++validCount;
+ if (r.name === base.name)
+ ++validCount;
+ return validCount;
+ }
+
+ property int result: test_proxy()
+}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index bd60093a7b..2d124da279 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -401,6 +401,7 @@ private slots:
void sequenceConversionMethod();
void proxyIteration();
void proxyHandlerTraps();
+ void lookupsDoNotBypassProxy();
void gcCrashRegressionTest();
void cmpInThrows();
void frozenQObject();
@@ -8034,7 +8035,7 @@ public:
void init(QV4::ExecutionEngine *v4, QV4::WeakValue *weakRef, bool *resultPtr)
{
- QV4::QObjectWrapper::wrap(v4, this);
+ (void) QV4::QObjectWrapper::wrap(v4, this); // Intentionally drop the wrapper
QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
this->resultPtr = resultPtr;
@@ -10154,6 +10155,17 @@ void tst_qqmlecmascript::proxyHandlerTraps()
QVERIFY(value.isString() && value.toString() == QStringLiteral("SUCCESS"));
}
+void tst_qqmlecmascript::lookupsDoNotBypassProxy()
+{
+ QQmlEngine engine;
+ // we need a component to have a proper compilation to byte code;
+ // otherwise, we don't actually end up with lookups
+ QQmlComponent comp(&engine, testFileUrl("lookupsDoNotBypassProxy.qml"));
+ QVERIFY(comp.isReady());
+ std::unique_ptr<QObject> obj { comp.create() };
+ QCOMPARE(obj->property("result").toInt(), 3);
+}
+
void tst_qqmlecmascript::cmpInThrows()
{
QJSEngine engine;
diff --git a/tests/auto/qml/qqmlimport/CMakeLists.txt b/tests/auto/qml/qqmlimport/CMakeLists.txt
index 803234787b..4e20f9bdba 100644
--- a/tests/auto/qml/qqmlimport/CMakeLists.txt
+++ b/tests/auto/qml/qqmlimport/CMakeLists.txt
@@ -35,6 +35,7 @@ qt_internal_add_test(tst_qqmlimport
SOURCES
tst_qqmlimport.cpp
LIBRARIES
+ Qt::CorePrivate
Qt::Gui
Qt::Qml
Qt::QmlPrivate
@@ -58,6 +59,23 @@ qt_internal_add_resource(tst_qqmlimport "preferred2"
"qmldir"
)
+qt_internal_add_resource(tst_qqmlimport "nomimport"
+ BASE
+ "data"
+ PREFIX
+ "/qqmlimport/"
+ FILES
+ "data/noimport/Main.qml"
+ "data/noimport/qmldir"
+)
+
+qt_internal_add_resource(tst_qqmlimport "qtconf"
+ PREFIX
+ "/"
+ FILES
+ "qmlimports.qt.conf"
+)
+
## Scopes:
#####################################################################
diff --git a/tests/auto/qml/qqmlimport/data/noimport/dirimported/Dirimported.qml b/tests/auto/qml/qqmlimport/data/noimport/dirimported/Dirimported.qml
new file mode 100644
index 0000000000..f374b7c95f
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/noimport/dirimported/Dirimported.qml
@@ -0,0 +1,5 @@
+import ".."
+
+TheThing {
+ width: 640
+}
diff --git a/tests/auto/qml/qqmlimport/data/noimport/redirected/Redirected.qml b/tests/auto/qml/qqmlimport/data/noimport/redirected/Redirected.qml
new file mode 100644
index 0000000000..d473b43d7b
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/noimport/redirected/Redirected.qml
@@ -0,0 +1,5 @@
+pragma Strict
+
+TheThing {
+ width: 640
+}
diff --git a/tests/auto/qml/qqmlimport/data/noimport/redirected/qmldir b/tests/auto/qml/qqmlimport/data/noimport/redirected/qmldir
new file mode 100644
index 0000000000..875be1000c
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/noimport/redirected/qmldir
@@ -0,0 +1 @@
+prefer :/qqmlimport/noimport/
diff --git a/tests/auto/qml/qqmlimport/qmlimports.qt.conf b/tests/auto/qml/qqmlimport/qmlimports.qt.conf
new file mode 100644
index 0000000000..3a63cc797f
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/qmlimports.qt.conf
@@ -0,0 +1,3 @@
+[Paths]
+Prefix = ""
+QmlImports = ":/a/path", ":/another/path", ":/even/more/path"
diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
index ff1513d0d6..7912be9b8e 100644
--- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
+++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
@@ -17,6 +17,7 @@
#include <QtCore/qscopeguard.h>
#include <QtCore/qlibraryinfo.h>
+#include <QtCore/private/qlibraryinfo_p.h>
class TheThing : public QObject
{
@@ -67,7 +68,9 @@ private slots:
void implicitWithDependencies();
void qualifiedScriptImport();
void invalidImportUrl();
+ void registerTypesFromImplicitImport_data();
void registerTypesFromImplicitImport();
+ void containsAllQtConfEntries();
private:
QQmlModuleRegistration noimportRegistration;
@@ -190,10 +193,19 @@ void tst_QQmlImport::invalidImportUrl()
":2 Cannot resolve URL for import \"file://./MyModuleName\"\n"));
}
+void tst_QQmlImport::registerTypesFromImplicitImport_data()
+{
+ QTest::addColumn<QUrl>("testfile");
+ QTest::addRow("immediate") << testFileUrl("noimport/Main.qml");
+ QTest::addRow("redirected") << testFileUrl("noimport/redirected/Redirected.qml");
+ QTest::addRow("dirimported") << testFileUrl("noimport/dirimported/Dirimported.qml");
+}
+
void tst_QQmlImport::registerTypesFromImplicitImport()
{
+ QFETCH(QUrl, testfile);
QQmlEngine engine;
- QQmlComponent c(&engine, testFileUrl("noimport/Main.qml"));
+ QQmlComponent c(&engine, testfile);
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
QScopedPointer<QObject> o(c.create());
QVERIFY(!o.isNull());
@@ -202,6 +214,22 @@ void tst_QQmlImport::registerTypesFromImplicitImport()
QCOMPARE(t->m_width, 640);
}
+void tst_QQmlImport::containsAllQtConfEntries()
+{
+ QString qtConfPath(u":/qmlimports.qt.conf");
+ QLibraryInfoPrivate::setQtconfManualPath(&qtConfPath);
+ QLibraryInfoPrivate::reload();
+ auto cleanup = qScopeGuard([](){
+ QLibraryInfoPrivate::setQtconfManualPath(nullptr);
+ QLibraryInfoPrivate::reload();
+ });
+ QQmlEngine engine;
+ auto importPaths = engine.importPathList();
+ QVERIFY(importPaths.contains(u"qrc:/a/path"));
+ QVERIFY(importPaths.contains(u"qrc:/another/path"));
+ QVERIFY(importPaths.contains(u"qrc:/even/more/path"));
+}
+
void tst_QQmlImport::testDesignerSupported()
{
std::unique_ptr<QQuickView> window = std::make_unique<QQuickView>();
diff --git a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
index 4dacc17f94..05e0b2870a 100644
--- a/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
+++ b/tests/auto/qml/qqmljsscope/tst_qqmljsscope.cpp
@@ -355,9 +355,9 @@ void tst_qqmljsscope::descriptiveNameOfNull()
property.setPropertyName(u"foo"_s);
property.setTypeName(u"baz"_s);
QQmlJSRegisterContent unscoped = QQmlJSRegisterContent::create(
- stored, property, QQmlJSRegisterContent::InvalidLookupIndex,
+ property, QQmlJSRegisterContent::InvalidLookupIndex,
QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::ScopeProperty,
- QQmlJSScope::ConstPtr());
+ QQmlJSScope::ConstPtr()).storedIn(stored);
QCOMPARE(unscoped.descriptiveName(), u"(invalid type)::foo with type baz (stored as bar)"_s);
}
diff --git a/tests/auto/qml/qqmllanguage/CMakeLists.txt b/tests/auto/qml/qqmllanguage/CMakeLists.txt
index cdab786a2f..9fff8f2118 100644
--- a/tests/auto/qml/qqmllanguage/CMakeLists.txt
+++ b/tests/auto/qml/qqmllanguage/CMakeLists.txt
@@ -33,6 +33,8 @@ qt_internal_add_test(tst_qqmllanguage
TESTDATA ${test_data}
)
+add_subdirectory(testhelper)
+
#### Keys ignored in scope 1:.:.:qqmllanguage.pro:<TRUE>:
# OTHER_FILES = "data/readonlyObjectProperty.qml"
# QML_IMPORT_NAME = "StaticTest"
diff --git a/tests/auto/qml/qqmllanguage/data/SingletonWithRequiredProperties/SingletonWithRequired1.qml b/tests/auto/qml/qqmllanguage/data/SingletonWithRequiredProperties/SingletonWithRequired1.qml
new file mode 100644
index 0000000000..f549e851a3
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/SingletonWithRequiredProperties/SingletonWithRequired1.qml
@@ -0,0 +1,6 @@
+pragma Singleton
+import QtQml
+
+QtObject {
+ required property int i
+}
diff --git a/tests/auto/qml/qqmllanguage/data/SingletonWithRequiredProperties/SingletonWithRequired2.qml b/tests/auto/qml/qqmllanguage/data/SingletonWithRequiredProperties/SingletonWithRequired2.qml
new file mode 100644
index 0000000000..1f9e7e3a42
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/SingletonWithRequiredProperties/SingletonWithRequired2.qml
@@ -0,0 +1,8 @@
+pragma Singleton
+import QtQml
+
+QtObject {
+ property QtObject o: QtObject {
+ required property int i
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/SingletonWithRequiredProperties/qmldir b/tests/auto/qml/qqmllanguage/data/SingletonWithRequiredProperties/qmldir
new file mode 100644
index 0000000000..46e397ca76
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/SingletonWithRequiredProperties/qmldir
@@ -0,0 +1,4 @@
+module SingletonWithRequiredProperties
+
+singleton SingletonWithRequired1 1.0 SingletonWithRequired1.qml
+singleton SingletonWithRequired2 1.0 SingletonWithRequired2.qml
diff --git a/tests/auto/qml/qqmllanguage/data/asValueType.qml b/tests/auto/qml/qqmllanguage/data/asValueType.qml
index 6a5500e344..b51dc9c6ec 100644
--- a/tests/auto/qml/qqmllanguage/data/asValueType.qml
+++ b/tests/auto/qml/qqmllanguage/data/asValueType.qml
@@ -10,4 +10,11 @@ QtObject {
property var e: ({x: 10, y: 20}) as point
property var f: "red" as withString
property var g: "green" as string
+ property rect bb
+ property var p: bb as size;
+ property var q: this as size;
+ property var r: ({}) as size;
+ property var s: 11 as size;
+ property var t: Component as size;
+ property var u: Qt as size;
}
diff --git a/tests/auto/qml/qqmllanguage/data/asValueTypeGood.qml b/tests/auto/qml/qqmllanguage/data/asValueTypeGood.qml
new file mode 100644
index 0000000000..777ada3848
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/asValueTypeGood.qml
@@ -0,0 +1,35 @@
+pragma ValueTypeBehavior: Assertable
+import QtQml as Q
+import StaticTest as S
+
+Q.QtObject {
+ property var a
+ property rect b: a as Q.rect
+ property bool c: a instanceof Q.rect
+ property bool d: ({x: 10, y: 20}) instanceof Q.point
+ property var e: ({x: 10, y: 20}) as Q.point
+ property var f: "red" as S.withString
+ property var g: "green" as Q.string
+
+ property var h: new S.withString("red")
+ property var i: {
+ let p = new Q.point;
+ p.x = 10
+ p.y = 20
+ return p
+ }
+
+ property var j: 4.0 as Q.int
+ property var k: (4.5 / 1.5) as Q.int
+ property var l: 5 as Q.double
+ property var m: "something" as Q.var
+ property var n: 1 as Q.bool
+ property var o: Infinity as Q.int
+
+ property var p: b as Q.size;
+ property var q: this as Q.size;
+ property var r: ({}) as Q.size;
+ property var s: 11 as Q.size;
+ property var t: Q.Component as Q.size;
+ property var u: Q.Qt as Q.size;
+}
diff --git a/tests/auto/qml/qqmllanguage/data/invokableCtors.qml b/tests/auto/qml/qqmllanguage/data/invokableCtors.qml
new file mode 100644
index 0000000000..35a8d7bf08
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/invokableCtors.qml
@@ -0,0 +1,12 @@
+import QtQml as QQ
+import Test as VV
+
+QQ.QtObject {
+ property QQ.QtObject oo: new QQ.QtObject()
+ property QQ.QtObject pp: new QQ.QtObject(oo)
+ property VV.vv v: new VV.vv("green")
+
+ property VV.InvokableSingleton i: new VV.InvokableSingleton(5, oo)
+ property VV.InvokableExtended k: new VV.InvokableExtended()
+ property VV.InvokableUncreatable l: new VV.InvokableUncreatable()
+}
diff --git a/tests/auto/qml/qqmllanguage/data/jsonArrayProperty.qml b/tests/auto/qml/qqmllanguage/data/jsonArrayProperty.qml
new file mode 100644
index 0000000000..5bd563a288
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/jsonArrayProperty.qml
@@ -0,0 +1,191 @@
+import QtQml
+import TypeWithQJsonArrayProperty
+
+TypeWithQJsonArrayProperty {
+ function jsArray() { return [1, 2, 3] }
+
+ jsonArray: jsArray()
+
+ property list<int> concatenatedJsonArray: jsonArray.concat([4, 5, 6])
+ property list<int> concatenatedJsArray: jsArray().concat([4, 5, 6])
+
+ property bool entriesMatch: {
+ var iterator = jsonArray.entries();
+ for (var [index, element] of jsArray().entries()) {
+ var v = iterator.next().value;
+ if (index !== v[0] || element !== v[1]) {
+ console.log(index, v[0], element, v[1]);
+ return false;
+ }
+ }
+
+ var iterator = jsArray().entries();
+ for (var [index, element] of jsonArray.entries()) {
+ var v = iterator.next().value;
+ if (index !== v[0] || element !== v[1]) {
+ console.log(index, v[0], element, v[1]);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ property bool jsonArrayEvery: jsonArray.every(element => element != 0)
+ property bool jsArrayEvery: jsArray().every(element => element != 0)
+
+ property list<int> jsonArrayFiltered: jsonArray.filter(element => element > 2)
+ property list<int> jsArrayFiltered: jsArray().filter(element => element > 2)
+
+ property int jsonArrayFind: jsonArray.find(element => element === 2)
+ property int jsArrayFind: jsArray().find(element => element === 2)
+
+ property int jsonArrayFindIndex: jsonArray.findIndex(element => element === 1)
+ property int jsArrayFindIndex: jsArray().findIndex(element => element === 1)
+
+ property string jsonArrayForEach
+ property string jsArrayForEach
+
+ property bool jsonArrayIncludes: jsonArray.includes(3)
+ property bool jsArrayIncludes: jsArray().includes(3)
+
+ property int jsonArrayIndexOf: jsonArray.indexOf(2)
+ property int jsArrayIndexOf: jsArray().indexOf(2)
+
+ property string jsonArrayJoin: jsonArray.join()
+ property string jsArrayJoin: jsArray().join()
+
+ property bool keysMatch: {
+ var iterator = jsonArray.keys();
+ for (var index of jsArray().keys()) {
+ var v = iterator.next().value;
+ if (index !== v) {
+ console.log(index, v);
+ return false;
+ }
+ }
+
+ var iterator = jsArray().keys();
+ for (var index of jsonArray.keys()) {
+ var v = iterator.next().value;
+ if (index !== v) {
+ console.log(index, v);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ property int jsonArrayLastIndexOf: jsonArray.lastIndexOf(1)
+ property int jsArrayLastIndexOf: jsArray().lastIndexOf(1)
+
+ property list<string> jsonArrayMap: jsonArray.map(element => element.toString())
+ property list<string> jsArrayMap: jsArray().map(element => element.toString())
+
+ property int jsonArrayReduce: jsonArray.reduce((acc, element) => acc - element, 40)
+ property int jsArrayReduce: jsArray().reduce((acc, element) => acc - element, 40)
+
+ property string jsonArrayReduceRight: jsonArray.reduceRight((acc, element) => acc + element.toString(), "")
+ property string jsArrayReduceRight: jsArray().reduceRight((acc, element) => acc + element.toString(), "")
+
+ property list<int> jsonArraySlice: jsonArray.slice(0, 1)
+ property list<int> jsArraySlice: jsArray().slice(0, 1)
+
+ property bool jsonArraySome: jsonArray.some(element => element === 1)
+ property bool jsArraySome: jsArray().some(element => element === 1)
+
+ property string stringifiedLocaleJsonArray: jsonArray.toLocaleString()
+ property string stringifiedLocaleJsArray: jsArray().toLocaleString()
+
+ property string stringifiedJsonArray: jsonArray.toString()
+ property string stringifiedJsArray: jsArray().toString()
+
+ property bool valuesMatch: {
+ var iterator = jsonArray.values();
+ for (var obj of jsArray().values()) {
+ var v = iterator.next().value;
+ if (obj !== v) {
+ console.log(obj, v);
+ return false;
+ }
+ }
+
+ var iterator = jsArray().values();
+ for (var obj of jsonArray.values()) {
+ var v = iterator.next().value;
+ if (obj !== v) {
+ console.log(obj, v);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // In-place mutation methods.
+ // Set by onCompleted if mutating jsonArray and then accessing it
+ // respects the mutation and the mutation behaves as for an array.
+ property bool jsonArrayWasCopiedWithin: false
+ property bool jsonArrayWasFilled: false
+ property bool jsonArrayWasPopped: false
+ property bool jsonArrayWasPushed: false
+ property bool jsonArrayWasReversed: false
+ property bool jsonArrayWasShifted: false
+ property bool jsonArrayWasSpliced: false
+ property bool jsonArrayWasUnshifted: false
+ property bool jsonArrayWasSorted: false
+
+ Component.onCompleted: {
+ function equals(lhs, rhs) {
+ return lhs.toString() === rhs.toString()
+ }
+
+ jsonArray.forEach(element => jsonArrayForEach += "-" + element + "-");
+ jsArray().forEach(element => jsArrayForEach += "-" + element + "-");
+
+ var array = jsArray()
+
+ jsonArray.copyWithin(1, 0, 1)
+ array.copyWithin(1, 0, 1)
+ jsonArrayWasCopiedWithin = equals(jsonArray, array)
+
+ jsonArray.fill(7, 0, 1)
+ array.fill(7, 0, 1)
+ jsonArrayWasFilled = equals(jsonArray, array)
+
+ jsonArray.pop()
+ array.pop()
+ jsonArrayWasPopped = equals(jsonArray, array)
+
+ jsonArray.push(23)
+ jsonArray.push(11)
+ jsonArray.push(54)
+ jsonArray.push(42)
+ array.push(23)
+ array.push(11)
+ array.push(54)
+ array.push(42)
+ jsonArrayWasPushed = equals(jsonArray, array)
+
+ jsonArray.reverse()
+ array.reverse()
+ jsonArrayWasReversed = equals(jsonArray, array)
+
+ jsonArray.shift()
+ array.shift()
+ jsonArrayWasShifted = equals(jsonArray, array)
+
+ jsonArray.splice(2, 1, [1, 2], 7, [1, 5])
+ array.splice(2, 1, [1, 2], 7, [1, 5])
+ jsonArrayWasSpliced = equals(jsonArray, array)
+
+ jsonArray.unshift(4, 71)
+ array.unshift(4, 71)
+ jsonArrayWasUnshifted = equals(jsonArray, array)
+
+ jsonArray.sort()
+ array.sort()
+ jsonArrayWasSorted = equals(jsonArray, array)
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/nestedVectors.qml b/tests/auto/qml/qqmllanguage/data/nestedVectors.qml
new file mode 100644
index 0000000000..0bcea52133
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nestedVectors.qml
@@ -0,0 +1,27 @@
+import Test
+import QtQml
+
+NestedVectors {
+ id: self
+
+ property var list1
+
+ Component.onCompleted: {
+ list1 = self.getList()
+
+ let list2 = []
+ let data1 = []
+ data1.push(2)
+ data1.push(3)
+ data1.push(4)
+
+ let data2 = []
+ data2.push(5)
+ data2.push(6)
+
+ list2.push(data1)
+ list2.push(data2)
+
+ self.setList(list2)
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/optimizedSequenceShift.qml b/tests/auto/qml/qqmllanguage/data/optimizedSequenceShift.qml
new file mode 100644
index 0000000000..32765895a0
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/optimizedSequenceShift.qml
@@ -0,0 +1,14 @@
+import QtQml
+
+QtObject {
+ id: root
+
+ property int changes: 0
+
+ property list<int> numbers: [1, 2, 3, 4, 5]
+ onNumbersChanged: ++changes
+
+ property var one: numbers.shift.bind([1,2,3])()
+
+ Component.onCompleted: root.numbers.shift()
+}
diff --git a/tests/auto/qml/qqmllanguage/testhelper/CMakeLists.txt b/tests/auto/qml/qqmllanguage/testhelper/CMakeLists.txt
new file mode 100644
index 0000000000..6a58889335
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/testhelper/CMakeLists.txt
@@ -0,0 +1,13 @@
+qt_policy(SET QTP0001 NEW)
+qt_add_library(tst_qqmllanguage_qmlmodule STATIC)
+qt_autogen_tools_initial_setup(tst_qqmllanguage_qmlmodule)
+qt_add_qml_module(tst_qqmllanguage_qmlmodule
+ URI testhelper
+ VERSION 1.0
+ SOURCES
+ "declarativelyregistered.h"
+ "declarativelyregistered.cpp"
+)
+
+qt_autogen_tools_initial_setup(tst_qqmllanguage_qmlmoduleplugin)
+target_link_libraries(tst_qqmllanguage PRIVATE tst_qqmllanguage_qmlmoduleplugin)
diff --git a/tests/auto/qml/qqmllanguage/testhelper/declarativelyregistered.cpp b/tests/auto/qml/qqmllanguage/testhelper/declarativelyregistered.cpp
new file mode 100644
index 0000000000..24fcd83d42
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/testhelper/declarativelyregistered.cpp
@@ -0,0 +1,7 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#include "declarativelyregistered.h"
+
+PurelyDeclarativeSingleton::PurelyDeclarativeSingleton() = default;
+
+#include "moc_declarativelyregistered.cpp"
diff --git a/tests/auto/qml/qqmllanguage/testhelper/declarativelyregistered.h b/tests/auto/qml/qqmllanguage/testhelper/declarativelyregistered.h
new file mode 100644
index 0000000000..4845cc68b9
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/testhelper/declarativelyregistered.h
@@ -0,0 +1,20 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef DECLARATIVELYREGISTERED_LANGUAGE_H
+#define DECLARATIVELYREGISTERED_LANGUAGE_H
+
+#include <QtCore/qobject.h>
+#include <QtQml/qqmlregistration.h>
+
+class PurelyDeclarativeSingleton : public QObject
+{
+ Q_OBJECT
+ QML_SINGLETON
+ QML_ELEMENT
+public:
+ PurelyDeclarativeSingleton();
+};
+
+
+#endif
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index ffff0a6979..526cca4b5b 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -174,6 +174,14 @@ void registerTypes()
qmlRegisterTypesAndRevisions<NonSingleton>("EnumScopeTest", 1);
qmlRegisterTypesAndRevisions<EnumProviderSingletonQml>("EnumScopeTest", 1);
+ qmlRegisterTypesAndRevisions<TypeWithQJsonArrayProperty>("TypeWithQJsonArrayProperty", 1);
+ qmlRegisterTypesAndRevisions<
+ InvokableSingleton,
+ InvokableExtended,
+ InvokableUncreatable,
+ InvokableValueType
+ >("Test", 1);
+ qmlRegisterTypesAndRevisions<NestedVectors>("Test", 1);
}
QVariant myCustomVariantTypeConverter(const QString &data)
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index bcf02c1cf9..ce6abf3504 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -6,6 +6,7 @@
#include <QtCore/qobject.h>
#include <QtCore/qrect.h>
#include <QtCore/qdatetime.h>
+#include <QtCore/qjsonarray.h>
#include <QtGui/qtransform.h>
#include <QtGui/qcolor.h>
#include <QtGui/qvector2d.h>
@@ -2942,4 +2943,104 @@ public:
}
};
+class TypeWithQJsonArrayProperty : public QObject {
+ Q_OBJECT
+ QML_ELEMENT
+
+ Q_PROPERTY(QJsonArray jsonArray READ jsonArray WRITE setJsonArray NOTIFY jsonArrayChanged)
+
+public:
+ TypeWithQJsonArrayProperty(QObject *parent = nullptr) : QObject(parent) {}
+
+ const QJsonArray& jsonArray() { return m_jsonArray; }
+ void setJsonArray(const QJsonArray& a) { m_jsonArray = a; }
+
+signals:
+ void jsonArrayChanged();
+
+private:
+ QJsonArray m_jsonArray;
+};
+
+class InvokableSingleton : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+public:
+ InvokableSingleton() = default;
+ Q_INVOKABLE InvokableSingleton(int a, QObject *parent) : QObject(parent), m_a(a) {}
+
+ int m_a = 0;
+};
+
+class InvokableExtension : public QObject
+{
+ Q_OBJECT
+public:
+ Q_INVOKABLE InvokableExtension(QObject *parent = nullptr) : QObject(parent) {}
+};
+
+class InvokableExtended : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_EXTENDED(InvokableExtension)
+
+public:
+ Q_INVOKABLE InvokableExtended() = default;
+};
+
+class InvokableUncreatable : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("no")
+
+public:
+ Q_INVOKABLE InvokableUncreatable() = default;
+};
+
+class InvokableValueType
+{
+ Q_GADGET
+ QML_VALUE_TYPE(vv)
+public:
+ Q_INVOKABLE InvokableValueType() = default;
+ Q_INVOKABLE InvokableValueType(const QString &s) : m_s(s) {}
+ QString m_s;
+};
+
+class NestedVectors : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+public:
+ NestedVectors(QObject *parent = nullptr) : QObject(parent)
+ {
+ std::vector<int> data;
+ data.push_back(1);
+ data.push_back(2);
+ data.push_back(3);
+ m_list.push_back(data);
+ data.clear();
+ data.push_back(4);
+ data.push_back(5);
+ m_list.push_back(data);
+ }
+
+ Q_INVOKABLE std::vector<std::vector<int>> getList()
+ {
+ return m_list;
+ }
+
+ Q_INVOKABLE void setList(std::vector<std::vector<int>> list)
+ {
+ m_list = list;
+ }
+
+private:
+ std::vector<std::vector<int>> m_list;
+};
+
#endif // TESTTYPES_H
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 2f382e8d8e..2212a40eee 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -38,7 +38,7 @@
#include <deque>
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_DARWIN)
#include <unistd.h>
#endif
@@ -48,7 +48,7 @@ DEFINE_BOOL_CONFIG_OPTION(qmlCheckTypes, QML_CHECK_TYPES)
static inline bool isCaseSensitiveFileSystem(const QString &path) {
Q_UNUSED(path);
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_DARWIN)
return pathconf(path.toLatin1().constData(), _PC_CASE_SENSITIVE);
#elif defined(Q_OS_WIN)
return false;
@@ -249,6 +249,8 @@ private slots:
void compositeSingletonSelectors();
void compositeSingletonRegistered();
void compositeSingletonCircular();
+ void compositeSingletonRequiredProperties();
+ void compositeSingletonRequiredProperties_data();
void singletonsHaveContextAndEngine();
@@ -410,7 +412,9 @@ private slots:
void objectAndGadgetMethodCallsRejectThisObject();
void objectAndGadgetMethodCallsAcceptThisObject();
+
void asValueType();
+ void asValueTypeGood();
void longConversion();
@@ -453,6 +457,12 @@ private slots:
void enumScopes();
void typedObjectList();
+ void invokableCtors();
+
+ void jsonArrayPropertyBehavesLikeAnArray();
+
+ void nestedVectors();
+ void optimizedSequenceShift();
private:
QQmlEngine engine;
@@ -4907,6 +4917,36 @@ void tst_qqmllanguage::compositeSingletonCircular()
QCOMPARE(o->property("value").toInt(), 2);
}
+void tst_qqmllanguage::compositeSingletonRequiredProperties()
+{
+ QFETCH(QString, warning);
+ QFETCH(QString, singletonName);
+ QQmlEngine engine;
+ engine.addImportPath(dataDirectory());
+ {
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, qPrintable(warning));
+ std::unique_ptr<QObject> singleton {engine.singletonInstance<QObject *>(
+ "SingletonWithRequiredProperties",
+ singletonName
+ )};
+ QVERIFY(!singleton);
+ }
+}
+
+void tst_qqmllanguage::compositeSingletonRequiredProperties_data()
+{
+ QTest::addColumn<QString>("warning");
+ QTest::addColumn<QString>("singletonName");
+
+ QString warning1 = testFileUrl("SingletonWithRequiredProperties/SingletonWithRequired1.qml").toString()
+ + ":5:5: Required property i was not initialized";
+ QString warning2 = testFileUrl("SingletonWithRequiredProperties/SingletonWithRequired2.qml").toString()
+ + ":6:9: Required property i was not initialized";
+
+ QTest::addRow("toplevelRequired") << warning1 << "SingletonWithRequired1";
+ QTest::addRow("subObjectRequired") << warning2 << "SingletonWithRequired2";
+}
+
void tst_qqmllanguage::singletonsHaveContextAndEngine()
{
QObject *qmlSingleton = nullptr;
@@ -5411,24 +5451,30 @@ void tst_qqmllanguage::namespacedPropertyTypes()
void tst_qqmllanguage::qmlTypeCanBeResolvedByName_data()
{
QTest::addColumn<QUrl>("componentUrl");
+ QTest::addColumn<QString>("name");
// Built-in C++ types
- QTest::newRow("C++ - Anonymous") << testFileUrl("quickTypeByName_anon.qml");
- QTest::newRow("C++ - Named") << testFileUrl("quickTypeByName_named.qml");
+ QTest::newRow("C++ - Anonymous") << testFileUrl("quickTypeByName_anon.qml")
+ << QStringLiteral("QtQuick/Item");
+ QTest::newRow("C++ - Named") << testFileUrl("quickTypeByName_named.qml")
+ << QStringLiteral("QtQuick/Item");
// Composite types with a qmldir
- QTest::newRow("QML - Anonymous - qmldir") << testFileUrl("compositeTypeByName_anon_qmldir.qml");
- QTest::newRow("QML - Named - qmldir") << testFileUrl("compositeTypeByName_named_qmldir.qml");
+ QTest::newRow("QML - Anonymous - qmldir") << testFileUrl("compositeTypeByName_anon_qmldir.qml")
+ << QStringLiteral("SimpleType");
+ QTest::newRow("QML - Named - qmldir") << testFileUrl("compositeTypeByName_named_qmldir.qml")
+ << QStringLiteral("SimpleType");
}
void tst_qqmllanguage::qmlTypeCanBeResolvedByName()
{
QFETCH(QUrl, componentUrl);
+ QFETCH(QString, name);
QQmlEngine engine;
QQmlComponent component(&engine, componentUrl);
VERIFY_ERRORS(0);
- QTest::ignoreMessage(QtMsgType::QtWarningMsg, "[object Object]"); // a bit crude, but it will do
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, qPrintable(name));
QScopedPointer<QObject> o(component.create());
QVERIFY(!o.isNull());
@@ -5717,6 +5763,9 @@ void tst_qqmllanguage::retrieveQmlTypeId()
QVERIFY(qmlTypeId("Test", 1, 0, "MyExtendedUncreateableBaseClass") >= 0);
QVERIFY(qmlTypeId("Test", 1, 0, "MyUncreateableBaseClass") >= 0);
QVERIFY(qmlTypeId("Test", 1, 0, "MyTypeObjectSingleton") >= 0);
+
+ // Must also work for declaratively registered types whose module wasn't imported so far
+ QVERIFY(qmlTypeId("testhelper", 1, 0, "PurelyDeclarativeSingleton") >= 0);
}
void tst_qqmllanguage::polymorphicFunctionLookup()
@@ -8059,7 +8108,60 @@ void tst_qqmllanguage::asValueType()
QTest::ignoreMessage(
QtWarningMsg,
+ "Could not find any constructor for value type QQmlRectFValueType "
+ "to call with value undefined");
+
+ QTest::ignoreMessage(
+ QtWarningMsg,
qPrintable(url.toString() + ":7:5: Unable to assign [undefined] to QRectF"_L1));
+
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ qPrintable(url.toString() + ":10: Coercing a value to QML/point using a type "
+ "assertion. This behavior is deprecated. Add 'pragma "
+ "ValueTypeBehavior: Assertable' to prevent it."_L1));
+
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ qPrintable(url.toString() + ":14: Coercing between incompatible value types mistakenly "
+ "yields null rather than undefined. Add 'pragma "
+ "ValueTypeBehavior: Assertable' to prevent this."_L1));
+
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ qPrintable(url.toString() + ":15: Coercing from instances of object types to value "
+ "types mistakenly yields null rather than undefined. Add "
+ "'pragma ValueTypeBehavior: Assertable' to prevent "
+ "this."_L1));
+
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ qPrintable(url.toString() + ":16: Coercing a value to QML/size using a type "
+ "assertion. This behavior is deprecated. Add 'pragma "
+ "ValueTypeBehavior: Assertable' to prevent it."_L1));
+
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ qPrintable(url.toString() + ":11: Coercing a value to StaticTest/withString using a "
+ "type assertion. This behavior is deprecated. Add 'pragma "
+ "ValueTypeBehavior: Assertable' to prevent it."_L1));
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ "Could not find any constructor for value type QQmlSizeFValueType to call "
+ "with value 11");
+
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ qPrintable(url.toString() + ":18: Coercing a value to QML/size using a type "
+ "assertion. This behavior is deprecated. Add 'pragma "
+ "ValueTypeBehavior: Assertable' to prevent it."_L1));
+
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ qPrintable(url.toString() + ":19: Coercing a value to QML/size using a type "
+ "assertion. This behavior is deprecated. Add 'pragma "
+ "ValueTypeBehavior: Assertable' to prevent it."_L1));
+
QScopedPointer<QObject> o(c.create());
QCOMPARE(o->property("a"), QVariant());
@@ -8082,6 +8184,84 @@ void tst_qqmllanguage::asValueType()
const QVariant string = o->property("g");
QCOMPARE(string.metaType(), QMetaType::fromType<QString>());
QCOMPARE(string.toString(), u"green");
+
+ const QVariant p = o->property("p");
+ QCOMPARE(p.metaType(), QMetaType::fromType<std::nullptr_t>());
+
+ const QVariant q = o->property("q");
+ QCOMPARE(q.metaType(), QMetaType::fromType<std::nullptr_t>());
+
+ const QVariant r = o->property("r");
+ QCOMPARE(r.metaType(), QMetaType::fromType<QSizeF>());
+ QCOMPARE(r.value<QSizeF>(), QSizeF());
+
+ const QVariant s = o->property("s");
+ QCOMPARE(s.metaType(), QMetaType());
+
+ const QVariant t = o->property("t");
+ QCOMPARE(t.metaType(), QMetaType::fromType<QSizeF>());
+ QCOMPARE(t.value<QSizeF>(), QSizeF());
+
+ const QVariant u = o->property("u");
+ QCOMPARE(u.metaType(), QMetaType::fromType<QSizeF>());
+ QCOMPARE(u.value<QSizeF>(), QSizeF());
+}
+
+void tst_qqmllanguage::asValueTypeGood()
+{
+ QQmlEngine engine;
+ const QUrl url = testFileUrl("asValueTypeGood.qml");
+ QQmlComponent c(&engine, url);
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ qPrintable(url.toString() + ":7:5: Unable to assign [undefined] to QRectF"_L1));
+ QScopedPointer<QObject> o(c.create());
+
+ QCOMPARE(o->property("a"), QVariant());
+ QCOMPARE(o->property("b").value<QRectF>(), QRectF());
+ QVERIFY(!o->property("c").toBool());
+
+ const QRectF rect(1, 2, 3, 4);
+ o->setProperty("a", QVariant(rect));
+ QCOMPARE(o->property("b").value<QRectF>(), rect);
+ QVERIFY(o->property("c").toBool());
+
+ QVERIFY(!o->property("d").toBool());
+ QVERIFY(!o->property("e").isValid());
+ QVERIFY(!o->property("f").isValid());
+
+ const QVariant string = o->property("g");
+ QCOMPARE(string.metaType(), QMetaType::fromType<QString>());
+ QCOMPARE(string.toString(), u"green");
+
+ const ValueTypeWithString withString = o->property("h").value<ValueTypeWithString>();
+ QCOMPARE(withString.toString(), u"red");
+
+ const QPointF point = o->property("i").value<QPointF>();
+ QCOMPARE(point.x(), 10.0);
+ QCOMPARE(point.y(), 20.0);
+
+ const QVariant j = o->property("j");
+ QCOMPARE(j.metaType(), QMetaType::fromType<int>());
+ QCOMPARE(j.toInt(), 4);
+
+ QVERIFY(!o->property("k").isValid());
+ QVERIFY(!o->property("l").isValid());
+
+ const QVariant m = o->property("m");
+ QCOMPARE(m.metaType(), QMetaType::fromType<QString>());
+ QCOMPARE(m.toString(), u"something");
+
+ QVERIFY(!o->property("n").isValid());
+ QVERIFY(!o->property("o").isValid());
+ QVERIFY(!o->property("p").isValid());
+ QVERIFY(!o->property("q").isValid());
+ QVERIFY(!o->property("r").isValid());
+ QVERIFY(!o->property("s").isValid());
+ QVERIFY(!o->property("t").isValid());
+ QVERIFY(!o->property("u").isValid());
}
void tst_qqmllanguage::typedEnums_data()
@@ -8659,6 +8839,128 @@ void tst_qqmllanguage::typedObjectList()
QVERIFY(list.at(&list, 0) != nullptr);
}
+void tst_qqmllanguage::jsonArrayPropertyBehavesLikeAnArray() {
+ QQmlEngine e;
+ QQmlComponent c(&e, testFileUrl("jsonArrayProperty.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QCOMPARE(o->property("concatenatedJsonArray"), o->property("concatenatedJsArray"));
+ QVERIFY(o->property("entriesMatch").toBool());
+ QCOMPARE(o->property("jsonArrayEvery"), o->property("jsArrayEvery"));
+ QCOMPARE(o->property("jsonArrayFiltered"), o->property("jsArrayFiltered"));
+ QCOMPARE(o->property("jsonArrayFind"), o->property("jsArrayFind"));
+ QCOMPARE(o->property("jsonArrayFindIndex"), o->property("jsArrayFindIndex"));
+ QCOMPARE(o->property("jsonArrayForEach"), o->property("jsArrayForEach"));
+ QCOMPARE(o->property("jsonArrayIncludes"), o->property("jsArrayIncludes"));
+ QCOMPARE(o->property("jsonArrayIndexOf"), o->property("jsArrayIndexOf"));
+ QCOMPARE(o->property("jsonArrayJoin"), o->property("jsArrayJoin"));
+ QVERIFY(o->property("keysMatch").toBool());
+ QCOMPARE(o->property("jsonArrayLastIndexOf"), o->property("jsArrayLastIndexOf"));
+ QCOMPARE(o->property("jsonArrayMap"), o->property("jsArrayMap"));
+ QCOMPARE(o->property("jsonArrayReduce"), o->property("jsArrayReduce"));
+ QCOMPARE(o->property("jsonArrayReduceRight"), o->property("jsArrayReduceRight"));
+ QCOMPARE(o->property("jsonArraySlice"), o->property("jsArraySlice"));
+ QCOMPARE(o->property("jsonArraySome"), o->property("jsArraySome"));
+ QCOMPARE(o->property("stringifiedLocaleJsonArray"), o->property("stringifiedLocaleJsArray"));
+ QCOMPARE(o->property("stringifiedJsonArray"), o->property("stringifiedJsArray"));
+ QVERIFY(o->property("valuesMatch").toBool());
+
+ QVERIFY(o->property("jsonArrayWasCopiedWithin").toBool());
+ QVERIFY(o->property("jsonArrayWasFilled").toBool());
+ QVERIFY(o->property("jsonArrayWasPopped").toBool());
+ QVERIFY(o->property("jsonArrayWasPushed").toBool());
+ QVERIFY(o->property("jsonArrayWasReversed").toBool());
+ QVERIFY(o->property("jsonArrayWasShifted").toBool());
+ QVERIFY(o->property("jsonArrayWasSpliced").toBool());
+ QVERIFY(o->property("jsonArrayWasUnshifted").toBool());
+ QVERIFY(o->property("jsonArrayWasSorted").toBool());
+}
+
+void tst_qqmllanguage::invokableCtors()
+{
+ QQmlEngine e;
+
+ const QUrl url = testFileUrl("invokableCtors.qml");
+
+ QQmlComponent c(&e, url);
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+
+ const QString urlString = url.toString();
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(
+ urlString + ":9: You are calling a Q_INVOKABLE constructor of "
+ "InvokableSingleton which is a singleton in QML."));
+
+ // Extended types look like types without any constructors.
+ // Therefore they aren't even FunctionObjects.
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(
+ urlString + ":10: TypeError: Type error"));
+
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(
+ urlString + ":11: You are calling a Q_INVOKABLE constructor of "
+ "InvokableUncreatable which is uncreatable in QML."));
+
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QObject *oo = qvariant_cast<QObject *>(o->property("oo"));
+ QVERIFY(oo);
+ QObject *pp = qvariant_cast<QObject *>(o->property("pp"));
+ QVERIFY(pp);
+ QCOMPARE(pp->parent(), oo);
+
+ InvokableValueType vv = qvariant_cast<InvokableValueType>(o->property("v"));
+ QCOMPARE(vv.m_s, "green");
+
+ InvokableSingleton *i = qvariant_cast<InvokableSingleton *>(o->property("i"));
+ QVERIFY(i);
+ QCOMPARE(i->m_a, 5);
+ QCOMPARE(i->parent(), oo);
+
+ QVariant k = o->property("k");
+ QCOMPARE(k.metaType(), QMetaType::fromType<InvokableExtended *>());
+ QCOMPARE(k.value<InvokableExtended *>(), nullptr);
+
+ InvokableUncreatable *l = qvariant_cast<InvokableUncreatable *>(o->property("l"));
+ QVERIFY(l);
+}
+
+void tst_qqmllanguage::nestedVectors()
+{
+ QQmlEngine e;
+ QQmlComponent c(&e, testFileUrl("nestedVectors.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ NestedVectors *n = qobject_cast<NestedVectors *>(o.data());
+ QVERIFY(n);
+
+ const std::vector<std::vector<int>> expected1 { { 1, 2, 3 }, { 4, 5 } };
+ const QVariant list1 = n->property("list1");
+ QCOMPARE(list1.metaType(), QMetaType::fromType<std::vector<std::vector<int>>>());
+ QCOMPARE(list1.value<std::vector<std::vector<int>>>(), expected1);
+
+ const std::vector<std::vector<int>> expected2 { { 2, 3, 4 }, { 5, 6 } };
+ QCOMPARE(n->getList(), expected2);
+}
+
+void tst_qqmllanguage::optimizedSequenceShift()
+{
+ QQmlEngine e;
+ QQmlComponent c(&e, testFileUrl("optimizedSequenceShift.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QCOMPARE(o->property("changes").toInt(), 2);
+
+ const QVariant one = o->property("one");
+ QCOMPARE(one.metaType(), QMetaType::fromType<int>());
+ QCOMPARE(one.toInt(), 1);
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
index e57eb1b65a..67e1591b8b 100644
--- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
@@ -17,7 +17,7 @@
#include <QtQuickShapes/private/qquickshapesglobal_p.h>
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_DARWIN)
// For _PC_CASE_SENSITIVE
#include <unistd.h>
#endif
@@ -242,9 +242,9 @@ void tst_qqmlmoduleplugin::incorrectPluginCase()
QString expectedError = QLatin1String("module \"org.qtproject.WrongCase\" plugin \"PluGin\" not found");
-#if defined(Q_OS_MAC) || defined(Q_OS_WIN32)
+#if defined(Q_OS_DARWIN) || defined(Q_OS_WIN32)
bool caseSensitive = true;
-#if defined(Q_OS_MAC)
+#if defined(Q_OS_DARWIN)
int res = pathconf(QDir::currentPath().toLatin1().constData(), _PC_CASE_SENSITIVE);
if (res == -1)
QSKIP("Could not establish case sensitivity of file system");
diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
index 0a8411ddcf..62f67e548f 100644
--- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
+++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp
@@ -547,7 +547,7 @@ void tst_qqmlparser::invalidNumericSeparator_data() {
QTest::addColumn<QString>("error");
QTest::newRow("Trailing numeric separator") << "1_" << "A trailing numeric separator is not allowed in numeric literals";
- QTest::newRow("Multiple numeric separators") << "1__2" << "There can be at most one numeric separator beetwen digits";
+ QTest::newRow("Multiple numeric separators") << "1__2" << "There can be at most one numeric separator between digits";
}
void tst_qqmlparser::invalidNumericSeparator() {
diff --git a/tests/auto/qml/qqmlqt/data/qtbug_125495.qml b/tests/auto/qml/qqmlqt/data/qtbug_125495.qml
new file mode 100644
index 0000000000..88f9cb259f
--- /dev/null
+++ b/tests/auto/qml/qqmlqt/data/qtbug_125495.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Item {
+ property font fontProperty: Qt.font({ styleName: "Some Style" });
+}
diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
index 9fea41104d..8139ec48d7 100644
--- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
+++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp
@@ -85,6 +85,8 @@ private slots:
void timeRoundtrip_data();
void timeRoundtrip();
+ void fontSetsStyleName();
+
private:
QQmlEngine engine;
};
@@ -1469,6 +1471,18 @@ void tst_qqmlqt::timeRoundtrip()
QCOMPARE(tp.m_getTime, tp.m_putTime);
}
+void tst_qqmlqt::fontSetsStyleName() {
+ QQmlComponent component(&engine, testFileUrl("qtbug_125495.qml"));
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != nullptr);
+
+ QFont f;
+ f.setStyleName("Some Style");
+
+ QCOMPARE(qvariant_cast<QFont>(object->property("fontProperty")), f);
+}
+
QTEST_MAIN(tst_qqmlqt)
#include "tst_qqmlqt.moc"
diff --git a/tests/auto/qml/qqmltimer/CMakeLists.txt b/tests/auto/qml/qqmltimer/CMakeLists.txt
index f66e054dc6..88d596be85 100644
--- a/tests/auto/qml/qqmltimer/CMakeLists.txt
+++ b/tests/auto/qml/qqmltimer/CMakeLists.txt
@@ -21,6 +21,7 @@ qt_internal_add_test(tst_qqmltimer
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
+ Qt::QmlMetaPrivate
Qt::QuickPrivate
)
diff --git a/tests/auto/qml/qqmltimer/tst_qqmltimer.cpp b/tests/auto/qml/qqmltimer/tst_qqmltimer.cpp
index a6c61abd57..495f7044f6 100644
--- a/tests/auto/qml/qqmltimer/tst_qqmltimer.cpp
+++ b/tests/auto/qml/qqmltimer/tst_qqmltimer.cpp
@@ -1,14 +1,18 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-#include <QtTest/QSignalSpy>
-#include <qtest.h>
-#include <QtQml/qqmlengine.h>
-#include <QtQml/qqmlcomponent.h>
-#include <QtQml/private/qqmltimer_p.h>
-#include <QtQuick/qquickitem.h>
-#include <QDebug>
-#include <QtCore/QPauseAnimation>
+
#include <private/qabstractanimation_p.h>
+#include <private/qqmltimer_p.h>
+
+#include <QtQuick/qquickitem.h>
+
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlengine.h>
+
+#include <QtTest/qsignalspy.h>
+#include <QtTest/qtest.h>
+
+#include <QtCore/qpauseanimation.h>
void consistentWait(int ms)
{
diff --git a/tests/auto/qml/qqmlvaluetypes/data/constructors.qml b/tests/auto/qml/qqmlvaluetypes/data/constructors.qml
new file mode 100644
index 0000000000..d94d6d8ad4
--- /dev/null
+++ b/tests/auto/qml/qqmlvaluetypes/data/constructors.qml
@@ -0,0 +1,14 @@
+import QtQuick as Q
+
+Q.QtObject {
+ property var point: new Q.point()
+ property var size: new Q.size()
+ property var rect: new Q.rect()
+ property var color: new Q.color()
+ property var vector2d: new Q.vector2d()
+ property var vector3d: new Q.vector3d()
+ property var vector4d: new Q.vector4d()
+ property var quaternion: new Q.quaternion()
+ property var matrix4x4: new Q.matrix4x4()
+ property var font: new Q.font()
+}
diff --git a/tests/auto/qml/qqmlvaluetypes/data/matrix4x4_invokables.qml b/tests/auto/qml/qqmlvaluetypes/data/matrix4x4_invokables.qml
index c28901956d..1827b57ca9 100644
--- a/tests/auto/qml/qqmlvaluetypes/data/matrix4x4_invokables.qml
+++ b/tests/auto/qml/qqmlvaluetypes/data/matrix4x4_invokables.qml
@@ -1,4 +1,4 @@
-import QtQuick 2.0
+import QtQuick
Item {
property bool success: false
@@ -6,6 +6,7 @@ Item {
property variant m1: Qt.matrix4x4(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4)
property variant m2: Qt.matrix4x4(5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8)
property variant m3: Qt.matrix4x4(123,22,6,42,55,54,67,77,777,1,112,22,55,6696,77,777)
+ property matrix4x4 m4: PlanarTransform.fromAffineMatrix(1, 2, 3, 4, 5, 6)
property variant v1: Qt.vector4d(1,2,3,4)
property variant v2: Qt.vector3d(1,2,3)
property real factor: 2.23
@@ -101,6 +102,7 @@ Item {
if (m1.transposed() != Qt.matrix4x4(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4)) success = false;
if (m1.fuzzyEquals(m2)) success = false;
if (!m1.fuzzyEquals(m2, 10)) success = false;
+ if (m4 != Qt.matrix4x4(1, 3, 0, 5, 2, 4, 0, 6, 0, 0, 1, 0, 0, 0, 0, 1)) success = false;
if (!testTransformation()) success = false;
if (!testMatrixMapping()) success = false;
}
diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
index 2634044238..ea521053ae 100644
--- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
+++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
@@ -78,6 +78,7 @@ private slots:
void writeBackOnFunctionCall();
void valueTypeConversions();
void readReferenceOnGetOwnProperty();
+ void constructors();
private:
QQmlEngine engine;
@@ -1832,6 +1833,28 @@ void tst_qqmlvaluetypes::readReferenceOnGetOwnProperty()
QVERIFY(o->property("allo").toBool());
}
+void tst_qqmlvaluetypes::constructors()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("constructors.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QCOMPARE(o->property("point"), QVariant(QPointF()));
+ QCOMPARE(o->property("size"), QVariant(QSizeF()));
+ QCOMPARE(o->property("rect"), QVariant(QRectF()));
+ QCOMPARE(o->property("color"), QVariant(QColor()));
+ QCOMPARE(o->property("vector2d"), QVariant(QVector2D()));
+ QCOMPARE(o->property("vector3d"), QVariant(QVector3D()));
+ QCOMPARE(o->property("vector4d"), QVariant(QVector4D()));
+ QCOMPARE(o->property("quaternion"), QVariant(QQuaternion()));
+ QCOMPARE(o->property("matrix4x4"), QVariant(QMatrix4x4()));
+ QCOMPARE(o->property("font"), QVariant(QFont()));
+
+}
+
#undef CHECK_TYPE_IS_NOT_VALUETYPE
QTEST_MAIN(tst_qqmlvaluetypes)
diff --git a/tests/auto/qml/qv4estable/tst_qv4estable.cpp b/tests/auto/qml/qv4estable/tst_qv4estable.cpp
index 45df62b23e..7d137ae7d2 100644
--- a/tests/auto/qml/qv4estable/tst_qv4estable.cpp
+++ b/tests/auto/qml/qv4estable/tst_qv4estable.cpp
@@ -18,7 +18,7 @@ void tst_qv4estable::checkRemoveAvoidsHeapBufferOverflow()
QV4::ESTable estable;
// Fill the ESTable with values so it is at max capacity.
- QCOMPARE_EQ(estable.m_capacity, 8);
+ QCOMPARE_EQ(estable.m_capacity, 8U);
for (uint i = 0; i < estable.m_capacity; ++i) {
estable.set(QV4::Value::fromUInt32(i), QV4::Value::fromUInt32(i));
}
@@ -27,8 +27,8 @@ void tst_qv4estable::checkRemoveAvoidsHeapBufferOverflow()
for (uint i = 0; i < estable.m_capacity; ++i) {
QVERIFY(estable.m_keys[i].sameValueZero(QV4::Value::fromUInt32(i)));
}
- QCOMPARE_EQ(estable.m_capacity, 8);
- QCOMPARE_EQ(estable.m_size, 8);
+ QCOMPARE_EQ(estable.m_capacity, 8U);
+ QCOMPARE_EQ(estable.m_size, 8U);
// Remove the first item from the set to verify that asan does not trip.
// Relies on the CI platform propagating asan flag to all tests.
diff --git a/tests/auto/qml/qv4mm/data/storeLocal.qml b/tests/auto/qml/qv4mm/data/storeLocal.qml
new file mode 100644
index 0000000000..8d48a8b23c
--- /dev/null
+++ b/tests/auto/qml/qv4mm/data/storeLocal.qml
@@ -0,0 +1,34 @@
+import QtQml
+
+QtObject {
+ id: root
+ property bool wasNotMarkedBefore: false
+ property bool wasMarkedAfter: false
+ property int result: -2
+ function f() {
+ let a = [1, 2, 3];
+ function inner() {
+ a = [4, 5, 6];
+ }
+ __forceJit(inner);
+ __setupGC();
+ root.wasNotMarkedBefore = !__isMarked(a);
+ inner();
+ root.wasMarkedAfter = __isMarked(a);
+ return a[0];
+ }
+ Component.onCompleted: {
+ if (!__forceJit(f)) {
+ root.result = -1;
+ return;
+ }
+ if (f() !== 4)
+ root.result = 1;
+ else if (!wasNotMarkedBefore)
+ root.result = 2;
+ else if (!wasMarkedAfter)
+ root.result = 3;
+ else
+ root.result = 0; // success
+ }
+}
diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
index 5bcdcd4624..7714beb3c7 100644
--- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp
+++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
@@ -13,6 +13,11 @@
#include <private/qv4identifiertable_p.h>
#include <private/qv4arraydata_p.h>
#include <private/qqmlcomponentattached_p.h>
+#include <private/qv4mapobject_p.h>
+#include <private/qv4setobject_p.h>
+#if QT_CONFIG(qml_jit)
+#include <private/qv4baselinejit_p.h>
+#endif
#include <QtQuickTestUtils/private/qmlutils_p.h>
@@ -37,6 +42,8 @@ private slots:
void sharedInternalClassDataMarking();
void gcTriggeredInOnDestroyed();
void weakValuesAssignedAfterThePhaseThatShouldHandleWeakValues();
+ void mapAndSetKeepValuesAlive();
+ void jittedStoreLocalMarksValue();
};
tst_qv4mm::tst_qv4mm()
@@ -502,6 +509,227 @@ void tst_qv4mm::weakValuesAssignedAfterThePhaseThatShouldHandleWeakValues()
QVERIFY(ddata->jsWrapper.valueRef()->heapObject()->inUse());
}
+void tst_qv4mm::mapAndSetKeepValuesAlive()
+{
+ {
+ QJSEngine jsEngine;
+ QV4::ExecutionEngine &engine = *jsEngine.handle();
+
+ QV4::Scope scope(&engine);
+ auto map = jsEngine.evaluate("new Map()");
+ QV4::ScopedFunctionObject afunction(scope, engine.memoryManager->alloc<QV4::FunctionObject>()); // hack, we just need about any function object
+ QV4::Value thisObject = QJSValuePrivate::asReturnedValue(&map);
+
+ QVERIFY(!engine.memoryManager->gcBlocked);
+ // no scoped classes, as that would defeat the point of the test
+ // we block the gc instead so that the allocation can't trigger the gc
+ engine.memoryManager->gcBlocked = QV4::MemoryManager::InCriticalSection;
+ QV4::Heap::String *key = engine.newString(QString::fromLatin1("key"));
+ QV4::Heap::String *value = engine.newString(QString::fromLatin1("value"));
+ QV4::Value values[2] = { QV4::Value::fromHeapObject(key), QV4::Value::fromHeapObject(value) };
+ engine.memoryManager->gcBlocked = QV4::MemoryManager::Unblocked;
+ QVERIFY(!key->isMarked());
+ QVERIFY(!value->isMarked());
+
+ auto sm = engine.memoryManager->gcStateMachine.get();
+ sm->reset();
+ while (sm->state != QV4::GCState::HandleQObjectWrappers) {
+ QV4::GCStateInfo& stateInfo = sm->stateInfoMap[int(sm->state)];
+ sm->state = stateInfo.execute(sm, sm->stateData);
+ }
+ QV4::MapPrototype::method_set(afunction.getPointer(), &thisObject, values, 2);
+
+ // check that we can still insert primitve values - they don't get marked
+ // but they also should not casue any corrpution - note that a weak map
+ // only accepts object keys
+ values[0] = QV4::Value::fromInt32(12);
+ values[1] = QV4::Value::fromInt32(13);
+ QV4::MapPrototype::method_set(afunction.getPointer(), &thisObject, values, 2);
+
+ QVERIFY(key->isMarked());
+ QVERIFY(value->isMarked());
+ bool gcComplete = engine.memoryManager->tryForceGCCompletion();
+ QVERIFY(gcComplete);
+ QVERIFY(key->inUse());
+ QVERIFY(value->inUse());
+ gc(engine);
+ QCOMPARE(map.property("size").toInt(), 2);
+ }
+ {
+ QJSEngine jsEngine;
+ QV4::ExecutionEngine &engine = *jsEngine.handle();
+
+ QV4::Scope scope(&engine);
+ auto map = jsEngine.evaluate("new WeakMap()");
+ QV4::ScopedFunctionObject afunction(scope, engine.memoryManager->alloc<QV4::FunctionObject>()); // hack, we just need about any function object
+ QV4::Value thisObject = QJSValuePrivate::asReturnedValue(&map);
+
+ QVERIFY(!engine.memoryManager->gcBlocked);
+ // no scoped classes, as that would defeat the point of the test
+ // we block the gc instead so that the allocation can't trigger the gc
+ engine.memoryManager->gcBlocked = QV4::MemoryManager::InCriticalSection;
+ QV4::Heap::Object *key = engine.newObject();
+ QV4::Heap::String *value = engine.newString(QString::fromLatin1("value"));
+ QV4::Value values[2] = { QV4::Value::fromHeapObject(key), QV4::Value::fromHeapObject(value) };
+ engine.memoryManager->gcBlocked = QV4::MemoryManager::Unblocked;
+ QVERIFY(!key->isMarked());
+ QVERIFY(!value->isMarked());
+
+ auto sm = engine.memoryManager->gcStateMachine.get();
+ sm->reset();
+ while (sm->state != QV4::GCState::HandleQObjectWrappers) {
+ QV4::GCStateInfo& stateInfo = sm->stateInfoMap[int(sm->state)];
+ sm->state = stateInfo.execute(sm, sm->stateData);
+ }
+ QV4::WeakMapPrototype::method_set(afunction.getPointer(), &thisObject, values, 2);
+ QVERIFY(!engine.hasException);
+ QVERIFY(key->isMarked());
+ QVERIFY(value->isMarked());
+ bool gcComplete = engine.memoryManager->tryForceGCCompletion();
+ QVERIFY(gcComplete);
+ QVERIFY(key->inUse());
+ QVERIFY(value->inUse());
+ gc(engine);
+ QCOMPARE(map.property("size").toInt(), 0);
+ }
+ {
+ QJSEngine jsEngine;
+ QV4::ExecutionEngine &engine = *jsEngine.handle();
+
+ QV4::Scope scope(&engine);
+ auto map = jsEngine.evaluate("new Set()");
+ QV4::ScopedFunctionObject afunction(scope, engine.memoryManager->alloc<QV4::FunctionObject>()); // hack, we just need about any function object
+ QV4::Value thisObject = QJSValuePrivate::asReturnedValue(&map);
+
+ QVERIFY(!engine.memoryManager->gcBlocked);
+ // no scoped classes, as that would defeat the point of the test
+ // we block the gc instead so that the allocation can't trigger the gc
+ engine.memoryManager->gcBlocked = QV4::MemoryManager::InCriticalSection;
+ QV4::Heap::Object *key = engine.newObject();
+ QV4::Value values[1] = { QV4::Value::fromHeapObject(key) };
+ engine.memoryManager->gcBlocked = QV4::MemoryManager::Unblocked;
+ QVERIFY(!key->isMarked());
+
+ auto sm = engine.memoryManager->gcStateMachine.get();
+ sm->reset();
+ while (sm->state != QV4::GCState::HandleQObjectWrappers) {
+ QV4::GCStateInfo& stateInfo = sm->stateInfoMap[int(sm->state)];
+ sm->state = stateInfo.execute(sm, sm->stateData);
+ }
+ QV4::SetPrototype::method_add(afunction.getPointer(), &thisObject, values, 1);
+ values[0] = QV4::Value::fromInt32(13);
+ QV4::SetPrototype::method_add(afunction.getPointer(), &thisObject, values, 1);
+ QVERIFY(!engine.hasException);
+ QVERIFY(key->isMarked());
+ bool gcComplete = engine.memoryManager->tryForceGCCompletion();
+ QVERIFY(gcComplete);
+ QVERIFY(key->inUse());
+ gc(engine);
+ QCOMPARE(map.property("size").toInt(), 2);
+ }
+ {
+ QJSEngine jsEngine;
+ QV4::ExecutionEngine &engine = *jsEngine.handle();
+
+ QV4::Scope scope(&engine);
+ auto map = jsEngine.evaluate("new WeakSet()");
+ QV4::ScopedFunctionObject afunction(scope, engine.memoryManager->alloc<QV4::FunctionObject>()); // hack, we just need about any function object
+ QV4::Value thisObject = QJSValuePrivate::asReturnedValue(&map);
+
+ QVERIFY(!engine.memoryManager->gcBlocked);
+ // no scoped classes, as that would defeat the point of the test
+ // we block the gc instead so that the allocation can't trigger the gc
+ engine.memoryManager->gcBlocked = QV4::MemoryManager::InCriticalSection;
+ QV4::Heap::Object *key = engine.newObject();
+ QV4::Value values[1] = { QV4::Value::fromHeapObject(key) };
+ engine.memoryManager->gcBlocked = QV4::MemoryManager::Unblocked;
+ QVERIFY(!key->isMarked());
+
+ auto sm = engine.memoryManager->gcStateMachine.get();
+ sm->reset();
+ while (sm->state != QV4::GCState::HandleQObjectWrappers) {
+ QV4::GCStateInfo& stateInfo = sm->stateInfoMap[int(sm->state)];
+ sm->state = stateInfo.execute(sm, sm->stateData);
+ }
+ QV4::WeakSetPrototype::method_add(afunction.getPointer(), &thisObject, values, 1);
+ QVERIFY(!engine.hasException);
+ QVERIFY(key->isMarked());
+ bool gcComplete = engine.memoryManager->tryForceGCCompletion();
+ QVERIFY(gcComplete);
+ QVERIFY(key->inUse());
+ gc(engine);
+ QCOMPARE(map.property("size").toInt(), 0);
+ }
+}
+
+QV4::ReturnedValue method_force_jit(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc)
+{
+#if QT_CONFIG(qml_jit)
+ auto *v4 =b->engine();
+
+ Q_ASSERT(argc == 1);
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::JavaScriptFunctionObject> functionObject(scope, argv[0]);
+ auto *func = static_cast<QV4::Heap::JavaScriptFunctionObject *>(functionObject->heapObject())->function;
+ Q_ASSERT(func);
+ func->interpreterCallCount = std::numeric_limits<int>::max();
+ if (!v4->canJIT(func))
+ return QV4::StaticValue::fromBoolean(false).asReturnedValue();
+ QV4::JIT::BaselineJIT(func).generate();
+ return QV4::StaticValue::fromBoolean(true).asReturnedValue();
+#else
+ return QV4::StaticValue::fromBoolean(false).asReturnedValue();
+#endif
+}
+
+QV4::ReturnedValue method_setup_gc_for_test(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *, int)
+{
+ auto *v4 =b->engine();
+ auto *mm = v4->memoryManager;
+ mm->runFullGC();
+
+ auto sm = v4->memoryManager->gcStateMachine.get();
+ sm->reset();
+ while (sm->state != QV4::GCState::MarkGlobalObject) {
+ QV4::GCStateInfo& stateInfo = sm->stateInfoMap[int(sm->state)];
+ sm->state = stateInfo.execute(sm, sm->stateData);
+ }
+
+ return QV4::Encode::undefined();
+}
+
+QV4::ReturnedValue method_is_marked(const QV4::FunctionObject *, const QV4::Value *, const QV4::Value *argv, int argc)
+{
+ Q_ASSERT(argc == 1);
+
+ auto h = argv[0].heapObject();
+ Q_ASSERT(h);
+ return QV4::Encode(h->isMarked());
+}
+
+void tst_qv4mm::jittedStoreLocalMarksValue()
+{
+ QQmlEngine engine;
+
+ auto *v4 = engine.handle();
+ auto globalObject = v4->globalObject;
+ globalObject->defineDefaultProperty(QStringLiteral("__setupGC"), method_setup_gc_for_test);
+ globalObject->defineDefaultProperty(QStringLiteral("__forceJit"), method_force_jit);
+ globalObject->defineDefaultProperty(QStringLiteral("__isMarked"), method_is_marked);
+
+ QQmlComponent comp(&engine, testFileUrl("storeLocal.qml"));
+ QVERIFY(comp.isReady());
+ std::unique_ptr<QObject> root {comp.create()};
+
+ QVERIFY(root);
+ bool ok = false;
+ int result = root->property("result").toInt(&ok);
+ QVERIFY(ok);
+ if (result == -1)
+ QSKIP("Could not run JIT");
+ QCOMPARE(result, 0);
+}
+
QTEST_MAIN(tst_qv4mm)
#include "tst_qv4mm.moc"
diff --git a/tests/auto/qmldom/domdata/domitem/crashes/bracketsInBinding.qml b/tests/auto/qmldom/domdata/domitem/crashes/bracketsInBinding.qml
new file mode 100644
index 0000000000..bef28ffc45
--- /dev/null
+++ b/tests/auto/qmldom/domdata/domitem/crashes/bracketsInBinding.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Item {
+ property int foo: {}
+}
diff --git a/tests/auto/qmldom/domdata/domitem/lambdas.qml b/tests/auto/qmldom/domdata/domitem/lambdas.qml
new file mode 100644
index 0000000000..c241bb77ae
--- /dev/null
+++ b/tests/auto/qmldom/domdata/domitem/lambdas.qml
@@ -0,0 +1,41 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Item {
+ signal helloSignal
+
+ function method() {
+ console.log("helloMethod");
+ let myLambda = function(a, b) { return a + b };
+ let myArrow = (v, w) => a + b;
+ }
+
+ onHelloSignal: function(x, y, z) { console.log("HelloLambda"); }
+
+ function testNestedFunctions() {
+ function nested(tic, tac, toe) { return tic + tac/3 + toe/2}
+ nested()
+ }
+
+ function generators() {
+ function *myGeneratorDeclaration(a, b) { yield 5 };
+ let myGenerator = function*(tic, tac, toe) { yield tic + tac - toe };
+ }
+
+ function *generatorInQmlObject() {
+ function nested(q,w,e,r) { return q + w + e - r; }
+ function *nested2(a,z,e,r) { yield a + z + e - r; yield 42; }
+ yield 4;
+ yield* nested2(1,2,3,4);
+ const t = (function (a) {
+ return a + 100;
+ });
+ }
+ function traditionalLambda() {
+ const tradition = (function (a) {
+ return a + 100;
+ });
+ }
+}
diff --git a/tests/auto/qmldom/domitem/tst_qmldomitem.h b/tests/auto/qmldom/domitem/tst_qmldomitem.h
index 97cc26bbd7..6c74b7f746 100644
--- a/tests/auto/qmldom/domitem/tst_qmldomitem.h
+++ b/tests/auto/qmldom/domitem/tst_qmldomitem.h
@@ -2874,6 +2874,9 @@ private slots:
QTest::addRow("lambda")
<< baseDir + u"/crashes/lambda.qml"_s;
+
+ QTest::addRow("bracketsInBinding")
+ << baseDir + u"/crashes/bracketsInBinding.qml"_s;
}
void crashes()
{
@@ -3189,6 +3192,157 @@ private slots:
envPtrChild->loadPendingDependencies();
}
+ void populateLazyFileBeforeCommitToBase()
+ {
+ DomItem qmlObject;
+ DomCreationOptions options;
+ options.setFlag(DomCreationOption::WithScriptExpressions);
+ options.setFlag(DomCreationOption::WithSemanticAnalysis);
+ options.setFlag(DomCreationOption::WithRecovery);
+
+ std::shared_ptr<DomEnvironment> envPtr = DomEnvironment::create(
+ qmltypeDirs, QQmlJS::Dom::DomEnvironment::Option::SingleThreaded, options);
+
+ const QString fileName{ QDir::cleanPath(baseDir + u"/propertyBindings.qml"_s) };
+
+ {
+ DomItem envChild = DomItem(envPtr).makeCopy(DomItem::CopyOption::EnvConnected).item();
+ auto envPtrChild = envChild.ownerAs<DomEnvironment>();
+ envPtrChild->loadFile(
+ FileToLoad::fromFileSystem(envPtrChild, fileName),
+ [&qmlObject](Path, const DomItem &, const DomItem &newIt) {
+ qmlObject = newIt.fileObject();
+ });
+ envPtrChild->loadPendingDependencies();
+
+ const DomItem childEnv = DomItem(envPtrChild->shared_from_this());
+ // populate the lazy file by accessing it via the DomItem interface
+ const DomItem mainComponent =
+ childEnv.field(Fields::qmlFileWithPath)
+ .key(fileName)
+ .field(Fields::currentItem)
+ .field(Fields::components)
+ .key(QString());
+ QVERIFY(mainComponent);
+
+ envPtrChild->commitToBase(DomItem(envPtrChild));
+ } // destroy the temporary environment that the file was loaded into
+
+ // also make sure that the main component also exists in the base environment after the
+ // commitToBase call.
+ const DomItem env = DomItem(envPtr->shared_from_this());
+ const DomItem mainComponent = env.field(Fields::qmlFileWithPath)
+ .key(fileName)
+ .field(Fields::currentItem)
+ .field(Fields::components)
+ .key(QString());
+ QVERIFY(mainComponent);
+ }
+
+ void populateLazyFileAfterCommitToBase()
+ {
+ DomItem qmlObject;
+ DomCreationOptions options;
+ options.setFlag(DomCreationOption::WithScriptExpressions);
+ options.setFlag(DomCreationOption::WithSemanticAnalysis);
+ options.setFlag(DomCreationOption::WithRecovery);
+
+ std::shared_ptr<DomEnvironment> envPtr = DomEnvironment::create(
+ qmltypeDirs, QQmlJS::Dom::DomEnvironment::Option::SingleThreaded, options);
+
+ const QString fileName{ QDir::cleanPath(baseDir + u"/propertyBindings.qml"_s) };
+
+ {
+ DomItem envChild = DomItem(envPtr).makeCopy(DomItem::CopyOption::EnvConnected).item();
+ auto envPtrChild = envChild.ownerAs<DomEnvironment>();
+ envPtrChild->loadFile(
+ FileToLoad::fromFileSystem(envPtrChild, fileName),
+ [&qmlObject](Path, const DomItem &, const DomItem &newIt) {
+ qmlObject = newIt.fileObject();
+ });
+ envPtrChild->loadPendingDependencies();
+ envPtrChild->commitToBase(DomItem(envPtrChild));
+ } // destroy the temporary environment that the file was loaded into
+
+ const DomItem env = DomItem(envPtr->shared_from_this());
+ // populate the lazy file by accessing it via the DomItem interface
+ const DomItem mainComponent = env.field(Fields::qmlFileWithPath)
+ .key(fileName)
+ .field(Fields::currentItem)
+ .field(Fields::components)
+ .key(QString());
+ QVERIFY(mainComponent);
+ }
+
+ void qtbug_124799()
+ {
+ // reproduces the completion crash in QTBUG-124799 that was actually not completion related:
+ // triggering the completion was triggering the population of a file, that led to a
+ // heap-use-after-free. The steps to reproduce the crash are following:
+ // 1. load a file in a temporary environment
+ // 2. grab an unpopulated qqmljsscope from the type resolver of the loaded file
+ // 3. destroy the temporary environment
+ // 4. update the loaded file with new content, to make sure the QQmlJSImporter (used to
+ // populate of qmlfiles) has no more strong references in the QmlFile.
+ // 5. populate the unpopulated qqmljsscope: its factory should have kept track that its
+ // environment is not the temporary one but the base one (because of the commitToBase()
+ // call) and use the correct QQmlJSImporter (if its the one from the temporary environment
+ // this will lead to the heap-use-after-free memory error you get when triggering
+ // completions before this fix)
+
+ DomItem qmlObject;
+ DomCreationOptions options;
+ options.setFlag(DomCreationOption::WithScriptExpressions);
+ options.setFlag(DomCreationOption::WithSemanticAnalysis);
+ options.setFlag(DomCreationOption::WithRecovery);
+
+ std::shared_ptr<DomEnvironment> envPtr = DomEnvironment::create(
+ qmltypeDirs, QQmlJS::Dom::DomEnvironment::Option::SingleThreaded, options);
+
+ const QString fileName{ QDir::cleanPath(baseDir + u"/propertyBindings.qml"_s) };
+
+ QQmlJSScope::ConstPtr populateAfterEnvironmentDestruction;
+
+ {
+ DomItem envChild = DomItem(envPtr).makeCopy(DomItem::CopyOption::EnvConnected).item();
+ auto envPtrChild = envChild.ownerAs<DomEnvironment>();
+ envPtrChild->loadFile(
+ FileToLoad::fromFileSystem(envPtrChild, fileName),
+ [&qmlObject](Path, const DomItem &, const DomItem &newIt) {
+ qmlObject = newIt.fileObject();
+ });
+ envPtrChild->loadPendingDependencies();
+
+ auto qmlFilePtr = qmlObject.ownerAs<QmlFile>();
+ auto resolver = qmlFilePtr->typeResolver();
+ // simulate completion by grabbing some type from the resolver
+ populateAfterEnvironmentDestruction = resolver->importedTypes()[u"Derived"_s].scope;
+ envPtrChild->commitToBase(DomItem(envPtrChild));
+ }
+
+ // update the file
+ {
+ DomItem envChild = DomItem(envPtr).makeCopy(DomItem::CopyOption::EnvConnected).item();
+ auto envPtrChild = envChild.ownerAs<DomEnvironment>();
+
+ // simulate user typing something
+ QFile file(fileName);
+ QVERIFY(file.open(QFile::ReadOnly));
+ const QString content = file.readAll();
+ const QString newContent = content + "\n // important comment here\n";
+ envPtrChild->loadFile(FileToLoad::fromMemory(envPtrChild, fileName, newContent),
+ [&qmlObject](Path, const DomItem &, const DomItem &newIt) {
+ qmlObject = newIt.fileObject();
+ });
+ envPtrChild->loadPendingDependencies();
+ envPtrChild->commitToBase(DomItem(envPtrChild));
+ }
+
+ // step 3: populate the lazy qqmljsscope, it should not crash
+ QCOMPARE(populateAfterEnvironmentDestruction->filePath(),
+ QDir::cleanPath(baseDir + u"/Derived.qml"_s));
+ }
+
void visitTreeFilter()
{
DomItem qmlObject;
@@ -3404,6 +3558,20 @@ private slots:
QVERIFY(comments.contains(u"/*Ast Comment*/ "_s));
}
+ void doNotCrashOnMissingLogger()
+ {
+ using namespace Qt::StringLiterals;
+ const QString testFile = QDir::cleanPath(baseDir + u"/astComments.qml"_s);
+ const DomItem fileObject = rootQmlObjectFromFile(testFile, qmltypeDirs).fileObject();
+ auto filePtr = fileObject.as<QmlFile>();
+ QVERIFY(filePtr);
+ auto typeResolver = filePtr->typeResolver();
+ QVERIFY(typeResolver);
+ auto logger = typeResolver->logger();
+ // make sure that the logger is not use-after-free by checking its content
+ QCOMPARE(logger->fileName(), testFile);
+ }
+
void commentLocations()
{
auto envPtr = DomEnvironment::create(
@@ -3445,6 +3613,314 @@ private slots:
QCOMPARE(locs, expctedCommentLocations);
}
+ void lambdas()
+ {
+ using namespace Qt::StringLiterals;
+ const QString testFile = baseDir + u"/lambdas.qml"_s;
+ const DomItem fileObject = rootQmlObjectFromFile(testFile, qmltypeDirs).fileObject();
+ const DomItem mainObject = fileObject.field(Fields::components)
+ .key(QString())
+ .index(0)
+ .field(Fields::objects)
+ .index(0);
+ {
+ const DomItem lambda = mainObject.field(Fields::methods)
+ .key(u"method"_s)
+ .index(0)
+ .field(Fields::body)
+ .field(Fields::scriptElement)
+ .field(Fields::statements)
+ .index(1)
+ .field(Fields::declarations)
+ .index(0)
+ .field(Fields::initializer);
+ QVERIFY(lambda);
+ QCOMPARE(lambda.internalKind(), DomType::ScriptFunctionExpression);
+ QCOMPARE(lambda.field(Fields::name).value().toString(), u"myLambda"_s);
+ QCOMPARE(lambda.field(Fields::parameters).indexes(), 2);
+ QCOMPARE(lambda.field(Fields::parameters).index(0).field(Fields::identifier).value().toString(), u"a");
+ QCOMPARE(lambda.field(Fields::parameters).index(1).field(Fields::identifier).value().toString(), u"b");
+
+ auto scope = lambda.semanticScope();
+ QVERIFY(scope);
+ QVERIFY(scope->jsIdentifier(u"b"_s));
+
+ const DomItem body = lambda.field(Fields::body);
+ QCOMPARE(body.internalKind(), DomType::ScriptBlockStatement);
+ }
+ }
+ void arrow()
+ {
+ using namespace Qt::StringLiterals;
+ const QString testFile = baseDir + u"/lambdas.qml"_s;
+ const DomItem fileObject = rootQmlObjectFromFile(testFile, qmltypeDirs).fileObject();
+ const DomItem mainObject = fileObject.field(Fields::components)
+ .key(QString())
+ .index(0)
+ .field(Fields::objects)
+ .index(0);
+ {
+ const DomItem arrow = mainObject.field(Fields::methods)
+ .key(u"method"_s)
+ .index(0)
+ .field(Fields::body)
+ .field(Fields::scriptElement)
+ .field(Fields::statements)
+ .index(2)
+ .field(Fields::declarations)
+ .index(0)
+ .field(Fields::initializer);
+ QVERIFY(arrow);
+ QCOMPARE(arrow.internalKind(), DomType::ScriptFunctionExpression);
+ QCOMPARE(arrow.field(Fields::name).value().toString(), u"myArrow"_s);
+ QCOMPARE(arrow.field(Fields::parameters).indexes(), 2);
+ QCOMPARE(arrow.field(Fields::parameters)
+ .index(0)
+ .field(Fields::identifier)
+ .value()
+ .toString(),
+ u"v");
+ QCOMPARE(arrow.field(Fields::parameters)
+ .index(1)
+ .field(Fields::identifier)
+ .value()
+ .toString(),
+ u"w");
+
+ auto scope = arrow.semanticScope();
+ QVERIFY(scope);
+ QVERIFY(scope->jsIdentifier(u"w"_s));
+
+ const DomItem body = arrow.field(Fields::body);
+ QCOMPARE(body.internalKind(), DomType::ScriptBlockStatement);
+ QCOMPARE(body.field(Fields::statements).indexes(), 1);
+ QCOMPARE(body.field(Fields::statements).index(0).internalKind(),
+ DomType::ScriptReturnStatement);
+ }
+ }
+ void lamdbaInBinding()
+ {
+ using namespace Qt::StringLiterals;
+ const QString testFile = baseDir + u"/lambdas.qml"_s;
+ const DomItem fileObject = rootQmlObjectFromFile(testFile, qmltypeDirs).fileObject();
+ const DomItem mainObject = fileObject.field(Fields::components)
+ .key(QString())
+ .index(0)
+ .field(Fields::objects)
+ .index(0);
+ {
+ const DomItem lambda = mainObject.field(Fields::bindings)
+ .key(u"onHelloSignal"_s)
+ .index(0)
+ .field(Fields::value)
+ .field(Fields::scriptElement);
+ QVERIFY(lambda);
+ QCOMPARE(lambda.internalKind(), DomType::ScriptFunctionExpression);
+ QCOMPARE(lambda.field(Fields::name).value().toString(), QString());
+ QCOMPARE(lambda.field(Fields::parameters).indexes(), 3);
+ QCOMPARE(lambda.field(Fields::parameters).index(0).field(Fields::identifier).value().toString(), u"x");
+ QCOMPARE(lambda.field(Fields::parameters).index(2).field(Fields::identifier).value().toString(), u"z");
+ auto scope = lambda.semanticScope();
+ QVERIFY(scope);
+ QVERIFY(scope->jsIdentifier(u"z"_s));
+ const DomItem body = lambda.field(Fields::body);
+ QCOMPARE(body.internalKind(), DomType::ScriptBlockStatement);
+ }
+ }
+ void nestedFunction()
+ {
+ using namespace Qt::StringLiterals;
+ const QString testFile = baseDir + u"/lambdas.qml"_s;
+ const DomItem fileObject = rootQmlObjectFromFile(testFile, qmltypeDirs).fileObject();
+ const DomItem mainObject = fileObject.field(Fields::components)
+ .key(QString())
+ .index(0)
+ .field(Fields::objects)
+ .index(0);
+ {
+ const DomItem nested = mainObject.field(Fields::methods)
+ .key(u"testNestedFunctions"_s)
+ .index(0)
+ .field(Fields::body)
+ .field(Fields::scriptElement)
+ .field(Fields::statements)
+ .index(0);
+ QVERIFY(nested);
+ QCOMPARE(nested.internalKind(), DomType::ScriptFunctionExpression);
+ QCOMPARE(nested.field(Fields::name).value().toString(), u"nested"_s);
+ QCOMPARE(nested.field(Fields::parameters).indexes(), 3);
+ QCOMPARE(nested.field(Fields::parameters)
+ .index(0)
+ .field(Fields::identifier)
+ .value()
+ .toString(),
+ u"tic");
+ QCOMPARE(nested.field(Fields::parameters)
+ .index(2)
+ .field(Fields::identifier)
+ .value()
+ .toString(),
+ u"toe");
+ const DomItem body = nested.field(Fields::body);
+ QCOMPARE(body.internalKind(), DomType::ScriptBlockStatement);
+ auto scope = nested.semanticScope();
+ QVERIFY(scope);
+ QVERIFY(scope->jsIdentifier(u"toe"_s));
+ }
+ }
+ void generatorDeclaration()
+ {
+ using namespace Qt::StringLiterals;
+ const QString testFile = baseDir + u"/lambdas.qml"_s;
+ const DomItem fileObject = rootQmlObjectFromFile(testFile, qmltypeDirs).fileObject();
+ const DomItem mainObject = fileObject.field(Fields::components)
+ .key(QString())
+ .index(0)
+ .field(Fields::objects)
+ .index(0);
+ {
+ const DomItem generator = mainObject.field(Fields::methods)
+ .key(u"generators"_s)
+ .index(0)
+ .field(Fields::body)
+ .field(Fields::scriptElement)
+ .field(Fields::statements)
+ .index(0);
+ QVERIFY(generator);
+ QCOMPARE(generator.internalKind(), DomType::ScriptFunctionExpression);
+ QCOMPARE(generator.field(Fields::name).value().toString(), u"myGeneratorDeclaration"_s);
+ QCOMPARE(generator.field(Fields::parameters).indexes(), 2);
+ QCOMPARE(generator.field(Fields::parameters)
+ .index(0)
+ .field(Fields::identifier)
+ .value()
+ .toString(),
+ u"a");
+ QCOMPARE(generator.field(Fields::parameters)
+ .index(1)
+ .field(Fields::identifier)
+ .value()
+ .toString(),
+ u"b");
+ const DomItem body = generator.field(Fields::body);
+ QCOMPARE(body.internalKind(), DomType::ScriptBlockStatement);
+ auto scope = generator.semanticScope();
+ QVERIFY(scope);
+ QVERIFY(scope->jsIdentifier(u"b"_s));
+
+ const DomItem yieldExpression =
+ generator.field(Fields::body).field(Fields::statements).index(0);
+ QCOMPARE(yieldExpression.internalKind(), DomType::ScriptYieldExpression);
+ QCOMPARE(yieldExpression.field(Fields::expression).value().toInteger(), 5);
+ }
+ }
+ void generatorExpression()
+ {
+ using namespace Qt::StringLiterals;
+ const QString testFile = baseDir + u"/lambdas.qml"_s;
+ const DomItem fileObject = rootQmlObjectFromFile(testFile, qmltypeDirs).fileObject();
+ const DomItem mainObject = fileObject.field(Fields::components)
+ .key(QString())
+ .index(0)
+ .field(Fields::objects)
+ .index(0);
+ {
+ const DomItem generator = mainObject.field(Fields::methods)
+ .key(u"generators"_s)
+ .index(0)
+ .field(Fields::body)
+ .field(Fields::scriptElement)
+ .field(Fields::statements)
+ .index(1)
+ .field(Fields::declarations)
+ .index(0)
+ .field(Fields::initializer);
+ QVERIFY(generator);
+ QCOMPARE(generator.internalKind(), DomType::ScriptFunctionExpression);
+ QCOMPARE(generator.field(Fields::name).value().toString(), u"myGenerator"_s);
+ QCOMPARE(generator.field(Fields::parameters).indexes(), 3);
+ QCOMPARE(generator.field(Fields::parameters)
+ .index(0)
+ .field(Fields::identifier)
+ .value()
+ .toString(),
+ u"tic");
+ QCOMPARE(generator.field(Fields::parameters)
+ .index(2)
+ .field(Fields::identifier)
+ .value()
+ .toString(),
+ u"toe");
+ const DomItem body = generator.field(Fields::body);
+ QCOMPARE(body.internalKind(), DomType::ScriptBlockStatement);
+ auto scope = generator.semanticScope();
+ QVERIFY(scope);
+ QVERIFY(scope->jsIdentifier(u"toe"_s));
+ }
+ }
+ void generatorDeclarationInQmlObject()
+ {
+ using namespace Qt::StringLiterals;
+ const QString testFile = baseDir + u"/lambdas.qml"_s;
+ const DomItem fileObject = rootQmlObjectFromFile(testFile, qmltypeDirs).fileObject();
+ const DomItem statements = fileObject.field(Fields::components)
+ .key(QString())
+ .index(0)
+ .field(Fields::objects)
+ .index(0)
+ .field(Fields::methods)
+ .key(u"generatorInQmlObject"_s)
+ .index(0)
+ .field(Fields::body)
+ .field(Fields::scriptElement)
+ .field(Fields::statements);
+ {
+ const DomItem nested = statements.index(0);
+ QVERIFY(nested);
+ QCOMPARE(nested.internalKind(), DomType::ScriptFunctionExpression);
+
+ const DomItem nested2 = statements.index(1);
+ QVERIFY(nested2);
+ QCOMPARE(nested2.internalKind(), DomType::ScriptFunctionExpression);
+
+ const DomItem yield = statements.index(2);
+ QVERIFY(yield);
+ QCOMPARE(yield.internalKind(), DomType::ScriptYieldExpression);
+
+ const DomItem yieldStar = statements.index(3);
+ QVERIFY(yieldStar);
+ QCOMPARE(yieldStar.internalKind(), DomType::ScriptYieldExpression);
+
+ }
+ }
+ void traditionalLambda()
+ {
+ using namespace Qt::StringLiterals;
+ const QString testFile = baseDir + u"/lambdas.qml"_s;
+ const DomItem fileObject = rootQmlObjectFromFile(testFile, qmltypeDirs).fileObject();
+ const DomItem initializer = fileObject.field(Fields::components)
+ .key(QString())
+ .index(0)
+ .field(Fields::objects)
+ .index(0)
+ .field(Fields::methods)
+ .key(u"traditionalLambda"_s)
+ .index(0)
+ .field(Fields::body)
+ .field(Fields::scriptElement)
+ .field(Fields::statements)
+ .index(0)
+ .field(Fields::declarations)
+ .index(0)
+ .field(Fields::initializer);
+ QVERIFY(initializer);
+ QCOMPARE(initializer.internalKind(), DomType::ScriptParenthesizedExpression);
+ const DomItem lambda = initializer.field(Fields::expression);
+ QVERIFY(lambda);
+ QCOMPARE(lambda.internalKind(), DomType::ScriptFunctionExpression);
+ }
+
+
private:
QString baseDir;
QStringList qmltypeDirs;
diff --git a/tests/auto/qmldom/reformatter/tst_reformatter.h b/tests/auto/qmldom/reformatter/tst_reformatter.h
index 31d80097c1..5cf800c80c 100644
--- a/tests/auto/qmldom/reformatter/tst_reformatter.h
+++ b/tests/auto/qmldom/reformatter/tst_reformatter.h
@@ -461,6 +461,13 @@ private slots:
<< QStringLiteral(u"function *g(a,b){}") << QStringLiteral(u"function* g(a, b) {}");
QTest::newRow("AnonymousGenerator") << QStringLiteral(u"let g=function * (a,b){}")
<< QStringLiteral(u"let g = function* (a, b) {}");
+ QTest::newRow("yield") << QStringLiteral(u"let g=function*(a,b){yield a;}")
+ << QStringLiteral(u"let g = function* (a, b) {\nyield a;\n}");
+ QTest::newRow("yield*") << QStringLiteral(u"let g=function*(a,b){yield*a;}")
+ << QStringLiteral(u"let g = function* (a, b) {\nyield* a;\n}");
+ QTest::newRow("yield*NoSemicolon")
+ << QStringLiteral(u"let g=function*(a,b){yield*a}")
+ << QStringLiteral(u"let g = function* (a, b) {\nyield* a;\n}");
}
// https://262.ecma-international.org/7.0/#prod-HoistableDeclaration
diff --git a/tests/auto/qmlls/modules/data/renameUsages/RenameMe.qml b/tests/auto/qmlls/modules/data/renameUsages/RenameMe.qml
new file mode 100644
index 0000000000..7680c63f95
--- /dev/null
+++ b/tests/auto/qmlls/modules/data/renameUsages/RenameMe.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Item {
+ property int helloProperty
+} \ No newline at end of file
diff --git a/tests/auto/qmlls/modules/data/renameUsages/RenameMe2.ui.qml b/tests/auto/qmlls/modules/data/renameUsages/RenameMe2.ui.qml
new file mode 100644
index 0000000000..b9197def63
--- /dev/null
+++ b/tests/auto/qmlls/modules/data/renameUsages/RenameMe2.ui.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Item {
+ property int helloProperty
+}
diff --git a/tests/auto/qmlls/modules/data/renameUsages/main.qml b/tests/auto/qmlls/modules/data/renameUsages/main.qml
new file mode 100644
index 0000000000..b59508f92f
--- /dev/null
+++ b/tests/auto/qmlls/modules/data/renameUsages/main.qml
@@ -0,0 +1,6 @@
+import QtQuick
+
+Item {
+ RenameMe {}
+ RenameMe2 {}
+}
diff --git a/tests/auto/qmlls/modules/tst_qmlls_modules.cpp b/tests/auto/qmlls/modules/tst_qmlls_modules.cpp
index d0851f15ff..fa050b0727 100644
--- a/tests/auto/qmlls/modules/tst_qmlls_modules.cpp
+++ b/tests/auto/qmlls/modules/tst_qmlls_modules.cpp
@@ -98,8 +98,10 @@ void tst_qmlls_modules::cleanup()
}
m_uriToClose.clear();
- disconnect(&m_server, nullptr, this, nullptr);
- m_server.closeWriteChannel();
+ // note: properly exit the language server
+ m_protocol->requestShutdown(nullptr, []() {});
+ m_protocol->notifyExit(nullptr);
+
m_server.waitForFinished();
QTRY_COMPARE(m_server.state(), QProcess::NotRunning);
QCOMPARE(m_server.exitStatus(), QProcess::NormalExit);
@@ -871,6 +873,12 @@ void tst_qmlls_modules::renameUsages_data()
QVERIFY(file.open(QIODeviceBase::ReadOnly));
jsIdentifierUsagesContent = QString::fromUtf8(file.readAll());
}
+ QString renamingContent;
+ {
+ QFile file(testFile("renameUsages/main.qml").toUtf8());
+ QVERIFY(file.open(QIODeviceBase::ReadOnly));
+ renamingContent = QString::fromUtf8(file.readAll());
+ }
// TODO: create workspace edit for the tests
QLspSpecification::WorkspaceEdit sumRenames{
@@ -906,6 +914,51 @@ void tst_qmlls_modules::renameUsages_data()
"Invalid EcmaScript identifier!",
std::nullopt,
};
+
+ const QString renameUsagesPath = u"renameUsages/main.qml"_s;
+ const QByteArray renameUsagesUri = testFileUrl("renameUsages/main.qml").toEncoded();
+ const QByteArray renameMeUri = testFileUrl("renameUsages/RenameMe.qml").toEncoded();
+ const QByteArray renameMe2Uri = testFileUrl("renameUsages/RenameMe2.ui.qml").toEncoded();
+
+ const QByteArray newFileUri = testFileUrl("renameUsages/HelloWorld.qml").toEncoded();
+ const QByteArray newFileUri2 = testFileUrl("renameUsages/HelloWorld.ui.qml").toEncoded();
+
+ {
+
+ const QLspSpecification::WorkspaceEdit qmlComponentRename{
+ std::nullopt,
+ QList<QLspSpecification::WorkspaceEdit::DocumentChange>{
+ TextDocumentEdit{
+ OptionalVersionedTextDocumentIdentifier{ { renameUsagesUri } },
+ {
+ TextEdit{ rangeFrom(renamingContent, 4, 5,
+ strlen("RenameMe")),
+ "HelloWorld" },
+ } },
+ RenameFile{ "rename", renameMeUri, newFileUri } }
+ };
+
+ QTest::addRow("renameQmlComponent")
+ << renameUsagesPath << 4 << 8 << u"HelloWorld"_s << qmlComponentRename << noError;
+ }
+
+ {
+ QLspSpecification::WorkspaceEdit qmlComponentRename{
+ std::nullopt,
+ QList<QLspSpecification::WorkspaceEdit::DocumentChange>{
+ TextDocumentEdit{
+ OptionalVersionedTextDocumentIdentifier{ { renameUsagesUri } },
+ {
+ TextEdit{ rangeFrom(renamingContent, 5, 5,
+ strlen("RenameMe2")),
+ "HelloWorld" },
+ } },
+ RenameFile{ "rename", renameMe2Uri, newFileUri2 } }
+ };
+
+ QTest::addRow("renameUiQmlComponent")
+ << renameUsagesPath << 5 << 8 << u"HelloWorld"_s << qmlComponentRename << noError;
+ }
}
void tst_qmlls_modules::compareQTextDocumentEdit(const TextDocumentEdit &a,
@@ -966,7 +1019,7 @@ void tst_qmlls_modules::renameUsages()
auto clean = [didFinish]() { *didFinish = true; };
m_protocol->requestRename(
params,
- [&](auto res) {
+ [&](auto &&res) {
QScopeGuard cleanup(clean);
auto *result = std::get_if<QLspSpecification::WorkspaceEdit>(&res);
@@ -991,6 +1044,22 @@ void tst_qmlls_modules::renameUsages()
compareQTextDocumentEdit(
std::get<TextDocumentEdit>(documentChanges[i]),
std::get<TextDocumentEdit>(expectedDocumentChanges[i]));
+ } else if (std::holds_alternative<RenameFile>(documentChanges[i])) {
+ const auto &actual = std::get<RenameFile>(documentChanges[i]);
+ const auto &expected = std::get<RenameFile>(expectedDocumentChanges[i]);
+
+ QCOMPARE(actual.kind, expected.kind);
+ QCOMPARE(expected.kind, "rename");
+ QCOMPARE(actual.oldUri, expected.oldUri);
+ QCOMPARE(actual.newUri, expected.newUri);
+ QCOMPARE(actual.options.has_value(), expected.options.has_value());
+ if (expected.options.has_value()) {
+ QCOMPARE(actual.options->overwrite, expected.options->overwrite);
+ QCOMPARE(actual.options->ignoreIfExists,
+ expected.options->ignoreIfExists);
+ }
+ QCOMPARE(actual.annotationId, expected.annotationId);
+
} else {
QFAIL("TODO: implement me!");
}
@@ -1498,7 +1567,7 @@ void tst_qmlls_modules::quickFixes()
static QQmlJS::Dom::DomItem fileObject(const QString &filePath)
{
QFile f(filePath);
- DomItem file;
+ QQmlJS::Dom::DomItem file;
if (!f.open(QIODevice::ReadOnly))
return file;
QString code = f.readAll();
diff --git a/tests/auto/qmlls/qqmlcodemodel/data/FileA.qml b/tests/auto/qmlls/qqmlcodemodel/data/FileA.qml
new file mode 100644
index 0000000000..5560aee727
--- /dev/null
+++ b/tests/auto/qmlls/qqmlcodemodel/data/FileA.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Item {
+
+}
diff --git a/tests/auto/qmlls/qqmlcodemodel/data/FileA2.qml b/tests/auto/qmlls/qqmlcodemodel/data/FileA2.qml
new file mode 100644
index 0000000000..7680c63f95
--- /dev/null
+++ b/tests/auto/qmlls/qqmlcodemodel/data/FileA2.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Item {
+ property int helloProperty
+} \ No newline at end of file
diff --git a/tests/auto/qmlls/qqmlcodemodel/data/FileB.qml b/tests/auto/qmlls/qqmlcodemodel/data/FileB.qml
new file mode 100644
index 0000000000..03cd2f9fb3
--- /dev/null
+++ b/tests/auto/qmlls/qqmlcodemodel/data/FileB.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+FileA {
+ property int helloPropertyInB
+}
diff --git a/tests/auto/qmlls/qqmlcodemodel/tst_qmlls_qqmlcodemodel.cpp b/tests/auto/qmlls/qqmlcodemodel/tst_qmlls_qqmlcodemodel.cpp
index f56839d99a..a3293769e5 100644
--- a/tests/auto/qmlls/qqmlcodemodel/tst_qmlls_qqmlcodemodel.cpp
+++ b/tests/auto/qmlls/qqmlcodemodel/tst_qmlls_qqmlcodemodel.cpp
@@ -128,4 +128,58 @@ void tst_qmlls_qqmlcodemodel::fileNamesToWatch()
QVERIFY(fileNames.contains(u"helloworld.h"_s));
}
+QString tst_qmlls_qqmlcodemodel::readFile(const QString &filename) const
+{
+ QFile f(testFile(filename));
+ if (!f.open(QFile::ReadOnly)) {
+ QTest::qFail("Can't read test file", __FILE__, __LINE__);
+ return {};
+ }
+ return f.readAll();
+}
+
+void tst_qmlls_qqmlcodemodel::openFiles()
+{
+ QmlLsp::QQmlCodeModel model;
+
+ const QByteArray fileAUrl = testFileUrl(u"FileA.qml"_s).toEncoded();
+ const QString fileAPath = testFile(u"FileA.qml"_s);
+
+ // open file A
+ model.newOpenFile(fileAUrl, 0, readFile(u"FileA.qml"_s));
+
+ QTRY_VERIFY_WITH_TIMEOUT(model.validEnv().field(Fields::qmlFileWithPath).key(fileAPath), 3000);
+
+ {
+ const DomItem fileAComponents = model.validEnv()
+ .field(Fields::qmlFileWithPath)
+ .key(fileAPath)
+ .field(Fields::currentItem)
+ .field(Fields::components);
+ // if there is no component then the lazy qml file was not loaded correctly.
+ QCOMPARE(fileAComponents.size(), 1);
+ }
+
+ model.newDocForOpenFile(fileAUrl, 1, readFile(u"FileA2.qml"_s));
+
+ {
+ const DomItem fileAComponents = model.validEnv()
+ .field(Fields::qmlFileWithPath)
+ .key(fileAPath)
+ .field(Fields::currentItem)
+ .field(Fields::components);
+ // if there is no component then the lazy qml file was not loaded correctly.
+ QCOMPARE(fileAComponents.size(), 1);
+
+ // also check if the property is there
+ const DomItem properties = fileAComponents.key(QString())
+ .index(0)
+ .field(Fields::objects)
+ .index(0)
+ .field(Fields::propertyDefs);
+ QVERIFY(properties);
+ QVERIFY(properties.key(u"helloProperty"_s));
+ }
+}
+
QTEST_MAIN(tst_qmlls_qqmlcodemodel)
diff --git a/tests/auto/qmlls/qqmlcodemodel/tst_qmlls_qqmlcodemodel.h b/tests/auto/qmlls/qqmlcodemodel/tst_qmlls_qqmlcodemodel.h
index 45c88d908e..a913f4bd19 100644
--- a/tests/auto/qmlls/qqmlcodemodel/tst_qmlls_qqmlcodemodel.h
+++ b/tests/auto/qmlls/qqmlcodemodel/tst_qmlls_qqmlcodemodel.h
@@ -23,6 +23,7 @@ class tst_qmlls_qqmlcodemodel : public QQmlDataTest
Q_OBJECT
public:
tst_qmlls_qqmlcodemodel();
+ QString readFile(const QString &filename) const;
private slots:
void buildPathsForFileUrl_data();
@@ -30,6 +31,7 @@ private slots:
void fileNamesToWatch();
void findFilePathsFromFileNames_data();
void findFilePathsFromFileNames();
+ void openFiles();
};
#endif // TST_QMLLS_QQMLCODEMODEL_H
diff --git a/tests/auto/qmlls/utils/CMakeLists.txt b/tests/auto/qmlls/utils/CMakeLists.txt
index ca4a26b051..ba81707b30 100644
--- a/tests/auto/qmlls/utils/CMakeLists.txt
+++ b/tests/auto/qmlls/utils/CMakeLists.txt
@@ -42,6 +42,21 @@ qt_internal_add_test(tst_qmlls_highlighting
TESTDATA ${test_data}
)
+qt_internal_add_test(tst_qmlls_documentationHints
+ SOURCES
+ tst_qmlls_documentationHints.cpp
+ DEFINES
+ QT_QMLLS_DOCUMENTATION_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+ LIBRARIES
+ Qt::Core
+ Qt::QmlDomPrivate
+ Qt::LanguageServerPrivate
+ Qt::Test
+ Qt::QuickTestUtilsPrivate
+ Qt::QmlLSPrivate
+ TESTDATA ${test_data}
+)
+
qt_internal_extend_target(tst_qmlls_utils CONDITION ANDROID OR IOS
DEFINES
QT_QMLLS_UTILS_DATADIR=":/domdata"
diff --git a/tests/auto/qmlls/utils/data/highlights/identifiers.qml b/tests/auto/qmlls/utils/data/highlights/identifiers.qml
deleted file mode 100644
index 7725b6d5e4..0000000000
--- a/tests/auto/qmlls/utils/data/highlights/identifiers.qml
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2023 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-
-import QtQuick
-
-Item {
- readonly property int test: 34
- signal pressed()
- function f() {
- let sum = 0, sum2 = 0
- for(let i = 1; i < 42; i = i + 2) {
- sum = test + i
- {
- let sum = 42; // another unrelated sum
- }
- }
- // signal and property changed
- testChanged();
- pressed();
- }
-
- // attached
- Keys.onPressed: {
- }
-
- // propertychanged handler
- onTestChanged: {
- f(); // method identifier
- }
-
- // signal handler
- onPressed: {}
-
- enum K { Plus}
- property int tt: Identifiers.Plus // component and enum value
-
-}
diff --git a/tests/auto/qmlls/utils/data/renaming/RenameMe.qml b/tests/auto/qmlls/utils/data/renaming/RenameMe.qml
new file mode 100644
index 0000000000..adc3da9800
--- /dev/null
+++ b/tests/auto/qmlls/utils/data/renaming/RenameMe.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Item {
+ property int i42
+} \ No newline at end of file
diff --git a/tests/auto/qmlls/utils/data/renaming/RenameMe2.ui.qml b/tests/auto/qmlls/utils/data/renaming/RenameMe2.ui.qml
new file mode 100644
index 0000000000..35320e03ff
--- /dev/null
+++ b/tests/auto/qmlls/utils/data/renaming/RenameMe2.ui.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Item {
+ property string i42
+} \ No newline at end of file
diff --git a/tests/auto/qmlls/utils/data/renaming/RenamedByQmldir.qml b/tests/auto/qmlls/utils/data/renaming/RenamedByQmldir.qml
new file mode 100644
index 0000000000..f97cbcf115
--- /dev/null
+++ b/tests/auto/qmlls/utils/data/renaming/RenamedByQmldir.qml
@@ -0,0 +1,4 @@
+import QtQuick
+
+Item {
+}
diff --git a/tests/auto/qmlls/utils/data/renaming/UnrelatedFile.qml b/tests/auto/qmlls/utils/data/renaming/UnrelatedFile.qml
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/qmlls/utils/data/renaming/UnrelatedFile.qml
diff --git a/tests/auto/qmlls/utils/data/renaming/main.qml b/tests/auto/qmlls/utils/data/renaming/main.qml
new file mode 100644
index 0000000000..10afda9773
--- /dev/null
+++ b/tests/auto/qmlls/utils/data/renaming/main.qml
@@ -0,0 +1,7 @@
+import QtQuick
+
+Item {
+ RenameMe {}
+ RenameMe2 {}
+ HelloWorld {}
+}
diff --git a/tests/auto/qmlls/utils/data/renaming/qmldir b/tests/auto/qmlls/utils/data/renaming/qmldir
new file mode 100644
index 0000000000..8cff297e26
--- /dev/null
+++ b/tests/auto/qmlls/utils/data/renaming/qmldir
@@ -0,0 +1,6 @@
+module renaming
+RenameMe 254.0 RenameMe.qml
+RenameMe2 254.0 RenameMe2.ui.qml
+RenameMe3 254.0 subfolder/RenameMe3.qml
+main 254.0 main.qml
+HelloWorld 254.0 RenamedByQmldir.qml \ No newline at end of file
diff --git a/tests/auto/qmlls/utils/tst_qmlls_documentationHints.cpp b/tests/auto/qmlls/utils/tst_qmlls_documentationHints.cpp
new file mode 100644
index 0000000000..dcb6f47df9
--- /dev/null
+++ b/tests/auto/qmlls/utils/tst_qmlls_documentationHints.cpp
@@ -0,0 +1,134 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "tst_qmlls_documentationHints.h"
+
+#include <QtQmlLS/private/qdochtmlparser_p.h>
+#include <QtQmlDom/private/qqmldomtop_p.h>
+
+tst_qmlls_documentationHints::tst_qmlls_documentationHints()
+ : QQmlDataTest(QT_QMLLS_DOCUMENTATION_DATADIR) , m_documentationDataDir(QT_QMLLS_DOCUMENTATION_DATADIR + "/documentationHints"_L1)
+{
+}
+
+void tst_qmlls_documentationHints::qdochtmlparser_data()
+{
+ using namespace QQmlJS::Dom;
+ QTest::addColumn<QString>("filePath");
+ QTest::addColumn<QString>("keyword");
+ QTest::addColumn<DomType>("domType");
+ QTest::addColumn<HtmlExtractor::ExtractionMode>("extractionMode");
+ QTest::addColumn<QString>("expectedDocumentation");
+
+ QTest::addRow("qml-object-type-extended-plaintext")
+ << testFile("qdochtmlparser/qml-qtqml-qtobject.html")
+ << "QtObject"
+ << DomType::QmlObject
+ << HtmlExtractor::ExtractionMode::Extended
+ << R"(The QtObject type is a non-visual element which contains only the objectName property.
+It can be useful to create a QtObject if you need an extremely lightweight type to enclose a set of custom properties:
+
+ import QtQuick
+
+ Item {
+ QtObject {
+ id: attributes
+ property string name
+ property int size
+ property variant attributes
+ }
+
+ Text { text: attributes.name }
+ }
+
+It can also be useful for C++ integration, as it is just a plain QObject. See the QObject documentation for further details.)";
+
+ QTest::addRow("qml-object-type-simplified-plaintext")
+ << testFile("qdochtmlparser/qml-qtqml-qtobject.html")
+ << "QtObject"
+ << DomType::QmlObject
+ << HtmlExtractor::ExtractionMode::Simplified
+ << R"(A basic QML type.)";
+
+ QTest::addRow("qml-property-simplified-plaintext")
+ << testFile("qdochtmlparser/qml-qtqml-qtobject.html")
+ << "objectName"
+ << DomType::PropertyDefinition
+ << HtmlExtractor::ExtractionMode::Simplified
+ << R"(This property holds the QObject::objectName for this specific object instance.)";
+
+ QTest::addRow("qml-property-simplified-plaintext-from-Qt5")
+ << testFile("qdochtmlparser/qml-qtqml-qtobject-qt-5.html")
+ << "objectName"
+ << DomType::PropertyDefinition
+ << HtmlExtractor::ExtractionMode::Simplified
+ << R"(This property holds the QObject::objectName for this specific object instance.)";
+
+ QTest::addRow("qml-property-simplified-plaintext")
+ << testFile("qdochtmlparser/qml-qtquick-item.html")
+ << "width"
+ << DomType::PropertyDefinition
+ << HtmlExtractor::ExtractionMode::Simplified
+ << R"(Defines the item's position and size. The default value is 0.)";
+
+ QTest::addRow("qml-group-property-simplified-plaintext")
+ << testFile("qdochtmlparser/qml-qtquick-item.html")
+ << "anchors.fill"
+ << DomType::PropertyDefinition
+ << HtmlExtractor::ExtractionMode::Simplified
+ << R"(Anchors provide a way to position an item by specifying its relationship with other items.)";
+ QTest::addRow("qml-functions")
+ << testFile("qdochtmlparser/qml-qtquick-item.html")
+ << "mapFromGlobal"
+ << DomType::MethodInfo
+ << HtmlExtractor::ExtractionMode::Simplified
+ << "Maps the point (x, y), which is in the global coordinate system, to the item's coordinate system,"
+ " and returns a point matching the mapped coordinate.";
+
+ QTest::addRow("qml-functions-list")
+ << testFile("qdochtmlparser/qml-qtquick-item.html")
+ << "mapFromItem"
+ << DomType::MethodInfo
+ << HtmlExtractor::ExtractionMode::Simplified
+ << "Maps the point (x, y) or rect (x, y, width, height), which is in item's coordinate system,"
+ " to this item's coordinate system, and returns a point or rect matching the mapped coordinate.";
+ QTest::addRow("qml-signal")
+ << testFile("qdochtmlparser/qml-qtquick-mousearea.html")
+ << "pressAndHold"
+ << DomType::MethodInfo
+ << HtmlExtractor::ExtractionMode::Simplified
+ << "This signal is emitted when there is a long press (currently 800ms). The mouse parameter provides information about the press, "
+ "including the x and y position of the press, and which button is pressed.";
+
+ // Some properties and methods can be shown as in groups in qt-docs, like width and height of Item.
+ QTest::addRow("multiple-entries")
+ << testFile("qdochtmlparser/qml-qtquick-mousearea.html")
+ << "pressAndHold"
+ << DomType::MethodInfo
+ << HtmlExtractor::ExtractionMode::Simplified
+ << "This signal is emitted when there is a long press (currently 800ms). The mouse parameter provides information about the press, "
+ "including the x and y position of the press, and which button is pressed.";
+}
+
+void tst_qmlls_documentationHints::qdochtmlparser()
+{
+ using namespace QQmlJS::Dom;
+ QFETCH(QString, filePath);
+ QFETCH(QString, keyword);
+ QFETCH(DomType, domType);
+ QFETCH(HtmlExtractor::ExtractionMode, extractionMode);
+ QFETCH(QString, expectedDocumentation);
+
+ const auto htmlCode = [](const QString &testFileName) {
+ QFile file(testFileName);
+ if (file.open(QIODeviceBase::ReadOnly | QIODevice::Text))
+ return QString::fromUtf8(file.readAll());
+ return QString{};
+ }(filePath);
+
+ ExtractDocumentation extractor(domType);
+ const auto actual = extractor.execute(htmlCode, keyword, extractionMode);
+ QCOMPARE(actual, expectedDocumentation);
+}
+
+QTEST_MAIN(tst_qmlls_documentationHints)
diff --git a/tests/auto/qmlls/utils/tst_qmlls_documentationHints.h b/tests/auto/qmlls/utils/tst_qmlls_documentationHints.h
new file mode 100644
index 0000000000..f3b0f4ddd1
--- /dev/null
+++ b/tests/auto/qmlls/utils/tst_qmlls_documentationHints.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef TST_QMLLS_DOCUMENTATION_H
+#define TST_QMLLS_DOCUMENTATION_H
+
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtCore/qobject.h>
+#include <QtTest/qtest.h>
+
+class tst_qmlls_documentationHints : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_qmlls_documentationHints();
+private slots:
+ void qdochtmlparser_data();
+ void qdochtmlparser();
+
+private:
+ QString m_documentationDataDir;
+};
+
+#endif // TST_QMLLS_DOCUMENTATION_H
diff --git a/tests/auto/qmlls/utils/tst_qmlls_utils.cpp b/tests/auto/qmlls/utils/tst_qmlls_utils.cpp
index c8808e2d7c..332dc13590 100644
--- a/tests/auto/qmlls/utils/tst_qmlls_utils.cpp
+++ b/tests/auto/qmlls/utils/tst_qmlls_utils.cpp
@@ -39,7 +39,7 @@ tst_qmlls_utils::createEnvironmentAndLoadFile(const QString &filePath)
{
CacheKey cacheKey = QDir::cleanPath(filePath + u"/.."_s);
if (auto entry = cache.find(cacheKey); entry != cache.end()) {
- DomItem env{ *entry };
+ QQmlJS::Dom::DomItem env{ *entry };
return { env, env.field(QQmlJS::Dom::Fields::qmlFileWithPath).key(filePath) };
};
@@ -663,7 +663,7 @@ void tst_qmlls_utils::findBaseObject()
struct UsageData
{
QString testFileName;
- QList<QQmlLSUtilsLocation> expectedUsages;
+ QQmlLSUtils::Usages expectedUsages;
};
void tst_qmlls_utils::findUsages_data()
@@ -679,33 +679,41 @@ void tst_qmlls_utils::findUsages_data()
return QString{};
};
- const auto makeUsages = [](const QString &fileName, QList<QQmlLSUtilsLocation> &locations) {
+ const auto makeUsages = [](const QString &fileName, QList<QQmlLSUtils::Location> &locations) {
UsageData data;
std::sort(locations.begin(), locations.end());
- data.expectedUsages = locations;
+ data.expectedUsages = { locations, {} };
data.testFileName = fileName;
return data;
};
{
- QList<QQmlLSUtilsLocation> expectedUsages;
+ QList<QQmlLSUtils::Location> expectedUsages;
const auto testFileName = testFile("findUsages/jsIdentifier/jsIdentifier.qml");
const auto testFileContent = readFileContent(testFileName);
{
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 8, 13, strlen("sum"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 10, 13, strlen("sum"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 10, 19, strlen("sum"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 8, 13,
+ strlen("sum"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 10, 13,
+ strlen("sum"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 10, 19,
+ strlen("sum"));
const auto sumUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findSumFromDeclaration") << 8 << 13 << sumUsages;
QTest::addRow("findSumFromUsage") << 10 << 20 << sumUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 17, strlen("i"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 24, strlen("i"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 32, strlen("i"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 36, strlen("i"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 10, 25, strlen("i"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 17,
+ strlen("i"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 24,
+ strlen("i"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 32,
+ strlen("i"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 36,
+ strlen("i"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 10, 25,
+ strlen("i"));
const auto iUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findIFromDeclaration") << 9 << 17 << iUsages;
QTest::addRow("findIFromUsage") << 9 << 24 << iUsages;
@@ -718,40 +726,54 @@ void tst_qmlls_utils::findUsages_data()
const auto testFileContent = readFileContent(testFileName);
const auto otherFileContent = readFileContent(otherFile);
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 8, 18, strlen("helloProperty"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 13, 13, strlen("helloProperty"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 13, 29, strlen("helloProperty"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 20, 9, strlen("helloProperty"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 21, 9, strlen("helloPropertyChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 23, 5, strlen("onHelloPropertyChanged"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 8, 18,
+ strlen("helloProperty"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 13, 13,
+ strlen("helloProperty"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 13, 29,
+ strlen("helloProperty"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 20, 9,
+ strlen("helloProperty"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 21, 9,
+ strlen("helloPropertyChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 23, 5,
+ strlen("onHelloPropertyChanged"));
const auto helloPropertyUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findPropertyFromDeclaration") << 8 << 18 << helloPropertyUsages;
QTest::addRow("findPropertyFromUsage") << 13 << 13 << helloPropertyUsages;
QTest::addRow("findPropertyFromUsage2") << 13 << 29 << helloPropertyUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 36, 20, strlen("helloProperty"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 38, 25, strlen("helloProperty"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 36, 20,
+ strlen("helloProperty"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 38, 25,
+ strlen("helloProperty"));
const auto subItemHelloPropertyUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findPropertyFromDeclarationInSubItem") << 38 << 25 << subItemHelloPropertyUsages;
QTest::addRow("findPropertyFromUsageInSubItem") << 36 << 20 << subItemHelloPropertyUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 27, 22, strlen("helloProperty"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 29, 20, strlen("helloProperty"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 27, 22,
+ strlen("helloProperty"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 29, 20,
+ strlen("helloProperty"));
const auto ICHelloPropertyUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findPropertyFromDeclarationInIC") << 27 << 22 << ICHelloPropertyUsages;
QTest::addRow("findPropertyFromUsageInIC") << 29 << 20 << ICHelloPropertyUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(otherFile, otherFileContent, 4, 18, strlen("helloProperty"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 42, 9, strlen("helloProperty"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 44, 20, strlen("helloProperty"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 46, 9, strlen("OnHelloPropertyChanged"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(otherFile, otherFileContent, 4, 18,
+ strlen("helloProperty"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 42, 9,
+ strlen("helloProperty"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 44, 20,
+ strlen("helloProperty"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 46, 9,
+ strlen("OnHelloPropertyChanged"));
const auto helloPropertyUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findPropertyFromOtherFile") << 42 << 13 << helloPropertyUsages;
@@ -770,35 +792,52 @@ void tst_qmlls_utils::findUsages_data()
const auto componentFileContent3 = readFileContent(componentFileName);
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 7, 18, strlen("p2"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 33, 31, strlen("p2"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 34, 37, strlen("p2"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 35, 43, strlen("p2"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 36, 49, strlen("p2"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 42, 26, strlen("p2"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 7, 18,
+ strlen("p2"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 33, 31,
+ strlen("p2"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 34, 37,
+ strlen("p2"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 35, 43,
+ strlen("p2"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 36, 49,
+ strlen("p2"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 42, 26,
+ strlen("p2"));
const auto p2Usages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findPropertyFromDeclaration2") << 7 << 18 << p2Usages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 29, 13, strlen("myNested"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 32, 17, strlen("myNested"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 33, 17, strlen("myNested"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 34, 17, strlen("myNested"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 35, 17, strlen("myNested"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 36, 17, strlen("myNested"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 29, 13,
+ strlen("myNested"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 32, 17,
+ strlen("myNested"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 33, 17,
+ strlen("myNested"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 34, 17,
+ strlen("myNested"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 35, 17,
+ strlen("myNested"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 36, 17,
+ strlen("myNested"));
const auto nestedUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findIdFromUsage") << 36 << 20 << nestedUsages;
QTest::addRow("findIdFromDefinition") << 29 << 17 << nestedUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 14, 35, strlen("inner"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 32, 32, strlen("inner"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 35, 32, strlen("inner"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 36, 32, strlen("inner"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 16, 9, strlen("inner"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 14, 35,
+ strlen("inner"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 32, 32,
+ strlen("inner"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 35, 32,
+ strlen("inner"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 36, 32,
+ strlen("inner"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 16, 9,
+ strlen("inner"));
const auto nestedComponent3Usages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findPropertyFromUsageInFieldMemberExpression")
<< 36 << 34 << nestedComponent3Usages;
@@ -807,12 +846,17 @@ void tst_qmlls_utils::findUsages_data()
<< 14 << 38 << nestedComponent3Usages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(componentFileName, componentFileContent, 4, 37, strlen("inner"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 50, 32, strlen("inner"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 52, 32, strlen("inner"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 53, 32, strlen("inner"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 54, 32, strlen("inner"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(componentFileName, componentFileContent,
+ 4, 37, strlen("inner"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 50, 32,
+ strlen("inner"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 52, 32,
+ strlen("inner"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 53, 32,
+ strlen("inner"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 54, 32,
+ strlen("inner"));
const auto nestedComponent3Usages = makeUsages(testFileName, expectedUsages);
const auto nestedComponent3UsagesFromOtherFile =
makeUsages(componentFileName, expectedUsages);
@@ -823,19 +867,21 @@ void tst_qmlls_utils::findUsages_data()
<< 4 << 38 << nestedComponent3UsagesFromOtherFile;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 35, 38, strlen("p2"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 20, 22, strlen("p2"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 35, 38,
+ strlen("p2"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 20, 22,
+ strlen("p2"));
const auto nestedComponent3P2Usages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findProperty2FromUsageInFieldMemberExpression")
<< 35 << 39 << nestedComponent3P2Usages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(componentFileName3, componentFileContent3,
- 5, 18, strlen("p2"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 53, 44,
- strlen("p2"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(componentFileName3, componentFileContent3,
+ 5, 18, strlen("p2"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 53, 44,
+ strlen("p2"));
const auto nestedComponent3P2Usages = makeUsages(testFileName, expectedUsages);
const auto nestedComponent3P2UsagesFromOtherFile = makeUsages(componentFileName3, expectedUsages);
QTest::addRow("findProperty2FromUsageInFieldMemberExpressionInOtherFile")
@@ -845,28 +891,40 @@ void tst_qmlls_utils::findUsages_data()
}
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
+ QList<QQmlLSUtils::Location> expectedUsages;
const auto testFileName = testFile("findUsages/idUsages/idUsages.qml");
const auto testFileContent = readFileContent(testFileName);
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 7, 9, strlen("rootId"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 11, 17, strlen("rootId"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 12, 20, strlen("rootId"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 17, 9, strlen("rootId"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 7, 9,
+ strlen("rootId"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 11, 17,
+ strlen("rootId"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 12, 20,
+ strlen("rootId"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 17, 9,
+ strlen("rootId"));
const auto rootIdUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findIdFromUsageInChild") << 12 << 20 << rootIdUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
+ QList<QQmlLSUtils::Location> expectedUsages;
const auto testFileName = testFile("findUsages/recursive/recursive.qml");
const auto testFileContent = readFileContent(testFileName);
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 8, 14, strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 10, 24, strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 10, 34, strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 10, 51, strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 10, 68, strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 12, 20, strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 15, 34, strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 19, 27, strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 8, 14,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 10, 24,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 10, 34,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 10, 51,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 10, 68,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 12, 20,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 15, 34,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 19, 27,
+ strlen("recursive"));
const auto recursiveUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findFunctionUsage") << 10 << 30 << recursiveUsages;
QTest::addRow("findFunctionUsage2") << 12 << 24 << recursiveUsages;
@@ -874,26 +932,26 @@ void tst_qmlls_utils::findUsages_data()
QTest::addRow("findFunctionUsageFromDefinition") << 8 << 17 << recursiveUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
+ QList<QQmlLSUtils::Location> expectedUsages;
const auto testFileName = testFile("findUsages/recursive/recursive.qml");
const auto testFileContent = readFileContent(testFileName);
const auto otherFileName = testFile("findUsages/recursive/RecursiveInOtherFile.qml");
const auto otherFileContent = readFileContent(otherFileName);
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 27, 61,
- strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(otherFileName, otherFileContent, 4, 14,
- strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(otherFileName, otherFileContent, 6, 24,
- strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(otherFileName, otherFileContent, 6, 34,
- strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(otherFileName, otherFileContent, 6, 51,
- strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(otherFileName, otherFileContent, 6, 68,
- strlen("recursive"));
- expectedUsages << QQmlLSUtilsLocation::from(otherFileName, otherFileContent, 8, 20,
- strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 27, 61,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(otherFileName, otherFileContent, 4, 14,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(otherFileName, otherFileContent, 6, 24,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(otherFileName, otherFileContent, 6, 34,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(otherFileName, otherFileContent, 6, 51,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(otherFileName, otherFileContent, 6, 68,
+ strlen("recursive"));
+ expectedUsages << QQmlLSUtils::Location::from(otherFileName, otherFileContent, 8, 20,
+ strlen("recursive"));
const auto recursiveUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findFunctionUsageFromOtherFile") << 27 << 64 << recursiveUsages;
@@ -909,26 +967,38 @@ void tst_qmlls_utils::findUsages_data()
const auto otherFileName = testFile("findUsages/signalsAndHandlers/widthChangedInAnotherFile.qml");
const auto otherFileContent = readFileContent(otherFileName);
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 8, 12, strlen("helloSignal"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 11, 9, strlen("helloSignal"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 13, 13, strlen("helloSignal"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 17, 17, strlen("helloSignal"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 21, 9, strlen("helloSignal"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 39, 5, strlen("onHelloSignal"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 8, 12,
+ strlen("helloSignal"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 11, 9,
+ strlen("helloSignal"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 13, 13,
+ strlen("helloSignal"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 17, 17,
+ strlen("helloSignal"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 21, 9,
+ strlen("helloSignal"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 39, 5,
+ strlen("onHelloSignal"));
const auto helloSignalUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findQmlSignalUsageFromDefinition") << 8 << 17 << helloSignalUsages;
QTest::addRow("findQmlSignalUsageFromUsage") << 13 << 17 << helloSignalUsages;
QTest::addRow("findQmlSignalUsageFromHandler") << 39 << 11 << helloSignalUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(otherFileName, otherFileContent, 5, 5, strlen("onWidthChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 23, 13, strlen("widthChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 27, 17, strlen("widthChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 28, 20, strlen("widthChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 34, 20, strlen("widthChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 33, 13, strlen("widthChanged"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(otherFileName, otherFileContent, 5, 5,
+ strlen("onWidthChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 23, 13,
+ strlen("widthChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 27, 17,
+ strlen("widthChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 28, 20,
+ strlen("widthChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 34, 20,
+ strlen("widthChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 33, 13,
+ strlen("widthChanged"));
const auto widthChangedUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findCppSignalUsageFromUsage") << 27 << 23 << widthChangedUsages;
QTest::addRow("findCppSignalUsageFromQualifiedUsage") << 28 << 23 << widthChangedUsages;
@@ -938,11 +1008,11 @@ void tst_qmlls_utils::findUsages_data()
{
const auto testFileName = testFile("findUsages/binding/binding.qml");
const auto testFileContent = readFileContent(testFileName);
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 18,
- strlen("helloPropertyBinding"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 10, 5,
- strlen("helloPropertyBinding"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 18,
+ strlen("helloPropertyBinding"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 10, 5,
+ strlen("helloPropertyBinding"));
const auto helloPropertyBindingUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findBindingUsagesFromDefinition") << 9 << 21 << helloPropertyBindingUsages;
QTest::addRow("findBindingUsagesFromBinding") << 10 << 19 << helloPropertyBindingUsages;
@@ -951,80 +1021,107 @@ void tst_qmlls_utils::findUsages_data()
const auto testFileName = testFile("findUsages/signalsAndHandlers/signalAndHandlers2.qml");
const auto testFileContent = readFileContent(testFileName);
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 7, 14, strlen("myHelloHandler"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 8, 20, strlen("myHelloHandler"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 14, 29, strlen("myHelloHandler"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 15, 24, strlen("myHelloHandler"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 23, 17, strlen("myHelloHandler"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 24, 24, strlen("myHelloHandler"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 25, 21, strlen("myHelloHandler"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 33, 19, strlen("myHelloHandler"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 42, 29, strlen("myHelloHandler"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 7, 14,
+ strlen("myHelloHandler"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 8, 20,
+ strlen("myHelloHandler"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 14, 29,
+ strlen("myHelloHandler"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 15, 24,
+ strlen("myHelloHandler"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 23, 17,
+ strlen("myHelloHandler"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 24, 24,
+ strlen("myHelloHandler"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 25, 21,
+ strlen("myHelloHandler"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 33, 19,
+ strlen("myHelloHandler"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 42, 29,
+ strlen("myHelloHandler"));
const auto myHelloHandlerUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findJSMethodFromUsageInBinding") << 8 << 27 << myHelloHandlerUsages;
QTest::addRow("findJSMethodFromDefinition") << 7 << 22 << myHelloHandlerUsages;
QTest::addRow("findJSMethodFromDefinition2") << 7 << 9 << myHelloHandlerUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 13, 18, strlen("checkHandlers"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 14, 5,
- strlen("onCheckHandlersChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 17, 9,
- strlen("checkHandlersChanged"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 13, 18,
+ strlen("checkHandlers"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 14, 5,
+ strlen("onCheckHandlersChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 17, 9,
+ strlen("checkHandlersChanged"));
const auto checkHandlersUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findQmlPropertyHandlerFromDefinition") << 13 << 18 << checkHandlersUsages;
QTest::addRow("findQmlPropertyHandlerFromHandler") << 14 << 5 << checkHandlersUsages;
QTest::addRow("findQmlPropertyHandlerFromSignalCall") << 17 << 9 << checkHandlersUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 15, 5,
- strlen("onChildrenChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 18, 9, strlen("childrenChanged"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 15, 5,
+ strlen("onChildrenChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 18, 9,
+ strlen("childrenChanged"));
const auto checkCppHandlersUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findCppPropertyHandlerFromHandler") << 15 << 5 << checkCppHandlersUsages;
QTest::addRow("findCppPropertyHandlerFromSignalCall") << 18 << 9 << checkCppHandlersUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 20, 18, strlen("_"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 23, 5, strlen("on_Changed"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 27, 9, strlen("_Changed"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 20, 18,
+ strlen("_"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 23, 5,
+ strlen("on_Changed"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 27, 9,
+ strlen("_Changed"));
const auto checkHandlersUsages2 = makeUsages(testFileName, expectedUsages);
QTest::addRow("findQmlPropertyHandler2FromDefinition") << 20 << 18 << checkHandlersUsages2;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 21, 18, strlen("______42"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 24, 5,
- strlen("on______42Changed"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 28, 9, strlen("______42Changed"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 21, 18,
+ strlen("______42"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 24, 5,
+ strlen("on______42Changed"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 28, 9,
+ strlen("______42Changed"));
const auto checkHandlersUsages3 = makeUsages(testFileName, expectedUsages);
QTest::addRow("findQmlPropertyHandler3FromDefinition") << 21 << 18 << checkHandlersUsages3;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 22, 18, strlen("_123a"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 25, 5, strlen("on_123AChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 29, 9, strlen("_123aChanged"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 22, 18,
+ strlen("_123a"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 25, 5,
+ strlen("on_123AChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 29, 9,
+ strlen("_123aChanged"));
const auto checkHandlersUsages4 = makeUsages(testFileName, expectedUsages);
QTest::addRow("findQmlPropertyHandler4FromDefinition") << 22 << 18 << checkHandlersUsages4;
}
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
+ QList<QQmlLSUtils::Location> expectedUsages;
const auto testFileName = testFile("findUsages/connections/connections.qml");
const auto testFileContent = readFileContent(testFileName);
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 9, strlen("onClicked"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 17, 23, strlen("clicked"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 33, 15, strlen("clicked"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 16, 22, strlen("onClicked"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 34, 15, strlen("clicked"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 18, 23, strlen("clicked"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 28, 9, strlen("onClicked"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 35, 15, strlen("clicked"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 9,
+ strlen("onClicked"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 17, 23,
+ strlen("clicked"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 33, 15,
+ strlen("clicked"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 16, 22,
+ strlen("onClicked"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 34, 15,
+ strlen("clicked"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 18, 23,
+ strlen("clicked"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 28, 9,
+ strlen("onClicked"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 35, 15,
+ strlen("clicked"));
const auto signalInConnection = makeUsages(testFileName, expectedUsages);
QTest::addRow("findSignalsInConnectionFromSignal") << 33 << 15 << signalInConnection;
QTest::addRow("findSignalsInConnectionFromHandler") << 9 << 9 << signalInConnection;
@@ -1035,41 +1132,51 @@ void tst_qmlls_utils::findUsages_data()
testFile("findUsages/parametersAndDeconstruction/parametersAndDeconstruction.qml");
const auto testFileContent = readFileContent(testFileName);
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 8, 30, strlen("a"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 16, strlen("a"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 8, 30,
+ strlen("a"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 16,
+ strlen("a"));
const auto aParamUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findMethodParameterA") << 9 << 16 << aParamUsages;
QTest::addRow("findMethodParameterAFromUsage") << 8 << 30 << aParamUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 8, 50, strlen("x"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 28, strlen("x"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 8, 50,
+ strlen("x"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 28,
+ strlen("x"));
const auto xParamUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findMethodParameterXDeconstructed") << 8 << 50 << xParamUsages;
QTest::addRow("findMethodParameterXDeconstructedFromUsage") << 9 << 28 << xParamUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 8, 53, strlen("y"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 32, strlen("y"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 8, 53,
+ strlen("y"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 32,
+ strlen("y"));
const auto yParamUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findMethodParameterYDeconstructed") << 8 << 53 << yParamUsages;
QTest::addRow("findMethodParameterYDeconstructedFromUsage") << 9 << 32 << yParamUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 8, 59, strlen("z"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 36, strlen("z"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 8, 59,
+ strlen("z"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 36,
+ strlen("z"));
const auto zParamUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("findMethodParameterZDeconstructed") << 8 << 59 << zParamUsages;
QTest::addRow("findMethodParameterZDeconstructedFromUsage") << 9 << 36 << zParamUsages;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 13, 14, strlen("a"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 14, 17, strlen("a"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 13, 14,
+ strlen("a"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 14, 17,
+ strlen("a"));
const auto deconstructedAUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("deconstructed") << 14 << 17 << deconstructedAUsages;
QTest::addRow("deconstructedFromDefinition") << 13 << 14 << deconstructedAUsages;
@@ -1081,12 +1188,17 @@ void tst_qmlls_utils::findUsages_data()
const auto otherFileName = testFile("findUsages/groupPropertyUsage/fontFamilyUsage.qml");
const auto otherFileContent = readFileContent(otherFileName);
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(otherFileName, otherFileContent, 5, 34, strlen("family"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 14, 17, strlen("family"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 23, 35, strlen("family"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 23, 10, strlen("family"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 33, 48, strlen("family"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(otherFileName, otherFileContent, 5, 34,
+ strlen("family"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 14, 17,
+ strlen("family"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 23, 35,
+ strlen("family"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 23, 10,
+ strlen("family"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 33, 48,
+ strlen("family"));
const auto groupPropertyUsages1 = makeUsages(testFileName, expectedUsages);
QTest::addRow("groupPropertyUsages1") << 14 << 17 << groupPropertyUsages1;
const auto groupPropertyUsages1FromOtherFile =
@@ -1095,13 +1207,19 @@ void tst_qmlls_utils::findUsages_data()
<< 5 << 37 << groupPropertyUsages1FromOtherFile;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 23, 5, strlen("font"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 24, 5, strlen("font"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 12, 13, strlen("font"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 23, 30, strlen("font"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 32, 41, strlen("font"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 33, 43, strlen("font"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 23, 5,
+ strlen("font"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 24, 5,
+ strlen("font"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 12, 13,
+ strlen("font"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 23, 30,
+ strlen("font"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 32, 41,
+ strlen("font"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 33, 43,
+ strlen("font"));
const auto groupPropertyUsages2 = makeUsages(testFileName, expectedUsages);
QTest::addRow("groupPropertyUsages2") << 23 << 5 << groupPropertyUsages2;
}
@@ -1110,20 +1228,26 @@ void tst_qmlls_utils::findUsages_data()
const auto testFileName =
testFile("findUsages/attachedPropertyUsage/attachedPropertyUsage.qml");
const auto testFileContent = readFileContent(testFileName);
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 5, strlen("Keys"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 12, 25, strlen("Keys"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 5,
+ strlen("Keys"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 12, 25,
+ strlen("Keys"));
const auto attachedPropertyUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("attachedPropertyUsages") << 12 << 25 << attachedPropertyUsages;
}
{
const auto testFileName = testFile("findUsages/inlineComponents/inlineComponents.qml");
const auto testFileContent = readFileContent(testFileName);
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 22, strlen("foo"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 10, 44, strlen("foo"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 14, 27, strlen("foo"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 20, 20, strlen("foo"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 22,
+ strlen("foo"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 10, 44,
+ strlen("foo"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 14, 27,
+ strlen("foo"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 20, 20,
+ strlen("foo"));
const auto inlineUsages = makeUsages(testFileName, expectedUsages);
QTest::addRow("inlineUsagesFromProperty") << 9 << 22 << inlineUsages;
QTest::addRow("inlineUsagesFromUsageOfBaseProperty") << 14 << 27 << inlineUsages;
@@ -1132,26 +1256,38 @@ void tst_qmlls_utils::findUsages_data()
{
const auto testFileName = testFile("findUsages/propertyChanges/propertyChanges.qml");
const auto testFileContent = readFileContent(testFileName);
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 8, 9, strlen("onClicked"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 16, 21, strlen("onClicked"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 19, 25, strlen("onClicked"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 25, 17, strlen("onClicked"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 8, 9,
+ strlen("onClicked"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 16, 21,
+ strlen("onClicked"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 19, 25,
+ strlen("onClicked"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 25, 17,
+ strlen("onClicked"));
const auto propertyChanges = makeUsages(testFileName, expectedUsages);
QTest::addRow("propertyChanges1") << 16 << 21 << propertyChanges;
}
{
const auto testFileName = testFile("findUsages/bindings/bindings.qml");
const auto testFileContent = readFileContent(testFileName);
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 11, 23, strlen("patronChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 14, 27, strlen("patronChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 21, 27, strlen("patronChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 27, 19, strlen("patronChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 27, 41, strlen("patronChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 34, 17, strlen("patronChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 13, 20, strlen("patronChanged"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 20, 23, strlen("\"patronChanged\""));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 11, 23,
+ strlen("patronChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 14, 27,
+ strlen("patronChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 21, 27,
+ strlen("patronChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 27, 19,
+ strlen("patronChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 27, 41,
+ strlen("patronChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 34, 17,
+ strlen("patronChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 13, 20,
+ strlen("patronChanged"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 20, 23,
+ strlen("\"patronChanged\""));
const auto bindings = makeUsages(testFileName, expectedUsages);
QTest::addRow("propertyInBindingsFromDecl") << 11 << 23 << bindings;
QTest::addRow("generalizedGroupPropertyBindings") << 27 << 19 << bindings;
@@ -1162,28 +1298,33 @@ void tst_qmlls_utils::findUsages_data()
const auto otherFileName = testFile("findUsages/enums/EnumsFromAnotherFile.qml");
const auto otherFileContent = readFileContent(otherFileName);
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 9, 9, strlen("Patron"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 22, 35, strlen("Patron"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 23, 34, strlen("Patron"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 9, 9,
+ strlen("Patron"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 22, 35,
+ strlen("Patron"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 23, 34,
+ strlen("Patron"));
const auto enums = makeUsages(testFileName, expectedUsages);
QTest::addRow("enumValuesFromDeclaration") << 9 << 9 << enums;
QTest::addRow("enumValuesFromUsage") << 22 << 35 << enums;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 8, 10, strlen("Cats"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 22, 30, strlen("Cats"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 8, 10,
+ strlen("Cats"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 22, 30,
+ strlen("Cats"));
const auto enums = makeUsages(testFileName, expectedUsages);
QTest::addRow("enumNameFromDeclaration") << 8 << 10 << enums;
QTest::addRow("enumNameFromUsage") << 22 << 30 << enums;
}
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 26, 46,
- strlen("FromAnotherUniverse"));
- expectedUsages << QQmlLSUtilsLocation::from(otherFileName, otherFileContent, 4, 68,
- strlen("FromAnotherUniverse"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 26, 46,
+ strlen("FromAnotherUniverse"));
+ expectedUsages << QQmlLSUtils::Location::from(otherFileName, otherFileContent, 4, 68,
+ strlen("FromAnotherUniverse"));
const auto enums = makeUsages(testFileName, expectedUsages);
QTest::addRow("enumNameFromDeclarationInOtherFile") << 26 << 50 << enums;
const auto enumsFromOtherFile = makeUsages(otherFileName, expectedUsages);
@@ -1194,13 +1335,19 @@ void tst_qmlls_utils::findUsages_data()
const auto testFileName = testFile("findUsages/inlineComponents/inlineComponents2.qml");
const auto testFileContent = readFileContent(testFileName);
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 4, 15, strlen("MyIC"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 5, 5, strlen("MyIC"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 5, 12, strlen("MyIC"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 5, 19, strlen("MyIC"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 6, 19, strlen("MyIC"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 6, 26, strlen("MyIC"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 4, 15,
+ strlen("MyIC"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 5, 5,
+ strlen("MyIC"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 5, 12,
+ strlen("MyIC"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 5, 19,
+ strlen("MyIC"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 6, 19,
+ strlen("MyIC"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 6, 26,
+ strlen("MyIC"));
const auto inlineComponents = makeUsages(testFileName, expectedUsages);
QTest::addRow("findICUsagesFromDefinition") << 4 << 16 << inlineComponents;
QTest::addRow("findICUsagesFromDefinition2") << 4 << 9 << inlineComponents;
@@ -1215,20 +1362,20 @@ void tst_qmlls_utils::findUsages_data()
testFile("findUsages/inlineComponents/InlineComponentProvider.qml");
const auto providerFileContent = readFileContent(providerFileName);
{
- QList<QQmlLSUtilsLocation> expectedUsages;
- expectedUsages << QQmlLSUtilsLocation::from(providerFileName, providerFileContent, 4,
- 15, strlen("IC1"));
- expectedUsages << QQmlLSUtilsLocation::from(providerFileName, providerFileContent, 5,
- 36, strlen("IC1"));
- expectedUsages << QQmlLSUtilsLocation::from(providerFileName, providerFileContent, 7, 5,
- strlen("IC1"));
- expectedUsages << QQmlLSUtilsLocation::from(providerFileName, providerFileContent, 17,
- 13, strlen("IC1"));
-
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 25, 38,
- strlen("IC1"));
- expectedUsages << QQmlLSUtilsLocation::from(testFileName, testFileContent, 25, 84,
- strlen("IC1"));
+ QList<QQmlLSUtils::Location> expectedUsages;
+ expectedUsages << QQmlLSUtils::Location::from(providerFileName, providerFileContent, 4,
+ 15, strlen("IC1"));
+ expectedUsages << QQmlLSUtils::Location::from(providerFileName, providerFileContent, 5,
+ 36, strlen("IC1"));
+ expectedUsages << QQmlLSUtils::Location::from(providerFileName, providerFileContent, 7,
+ 5, strlen("IC1"));
+ expectedUsages << QQmlLSUtils::Location::from(providerFileName, providerFileContent, 17,
+ 13, strlen("IC1"));
+
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 25, 38,
+ strlen("IC1"));
+ expectedUsages << QQmlLSUtils::Location::from(testFileName, testFileContent, 25, 84,
+ strlen("IC1"));
{
const auto usagesForTestFile = makeUsages(testFileName, expectedUsages);
@@ -1255,7 +1402,13 @@ void tst_qmlls_utils::findUsages()
QFETCH(int, line);
QFETCH(int, character);
QFETCH(UsageData, data);
- QVERIFY(std::is_sorted(data.expectedUsages.begin(), data.expectedUsages.end()));
+
+ {
+ auto usagesInFilename = data.expectedUsages.usagesInFilename();
+ QVERIFY(std::is_sorted(usagesInFilename.begin(), usagesInFilename.end()));
+ auto usagesInFile = data.expectedUsages.usagesInFile();
+ QVERIFY(std::is_sorted(usagesInFile.begin(), usagesInFile.end()));
+ }
auto [env, file] = createEnvironmentAndLoadFile(data.testFileName);
@@ -1275,17 +1428,19 @@ void tst_qmlls_utils::findUsages()
if constexpr (enable_debug_output) {
if (usages != data.expectedUsages) {
qDebug() << "Got:\n";
- for (auto &x : usages) {
+ for (auto &x : usages.usagesInFile()) {
qDebug() << x.filename << "(" << x.sourceLocation.startLine << ", "
<< x.sourceLocation.startColumn << "), " << x.sourceLocation.offset << "+"
<< x.sourceLocation.length;
}
+ qDebug() << "with usages in filenames:" << usages.usagesInFilename();
qDebug() << "But expected: \n";
- for (auto &x : data.expectedUsages) {
+ for (auto &x : data.expectedUsages.usagesInFile()) {
qDebug() << x.filename << "(" << x.sourceLocation.startLine << ", "
<< x.sourceLocation.startColumn << "), " << x.sourceLocation.offset << "+"
<< x.sourceLocation.length;
}
+ qDebug() << "with usages in filenames:" << data.expectedUsages.usagesInFilename();
}
}
@@ -1299,7 +1454,7 @@ void tst_qmlls_utils::renameUsages_data()
QTest::addColumn<int>("line");
QTest::addColumn<int>("character");
QTest::addColumn<QString>("newName");
- QTest::addColumn<QList<QQmlLSUtilsEdit>>("expectedRenames");
+ QTest::addColumn<QQmlLSUtils::RenameUsages>("expectedRenames");
QTest::addColumn<QString>("expectedError");
const QString testFileName = testFile(u"JSUsages.qml"_s);
@@ -1308,97 +1463,140 @@ void tst_qmlls_utils::renameUsages_data()
const QString testFileFromAnotherFileContent = readFileContent(testFileNameFromAnotherFile);
const QString noError;
- const QList<QQmlLSUtilsEdit> noRenames;
-
- QList<QQmlLSUtilsEdit> methodFRename{
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 72, 14, strlen("recursive"),
- u"newNameNewMe"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 74, 24, strlen("recursive"),
- u"newNameNewMe"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 74, 34, strlen("recursive"),
- u"newNameNewMe"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 74, 51, strlen("recursive"),
- u"newNameNewMe"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 74, 68, strlen("recursive"),
- u"newNameNewMe"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 76, 20, strlen("recursive"),
- u"newNameNewMe"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 79, 34, strlen("recursive"),
- u"newNameNewMe"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 84, 27, strlen("recursive"),
- u"newNameNewMe"_s),
+ const QQmlLSUtils::RenameUsages noRenames;
+
+ QQmlLSUtils::RenameUsages methodFRename{
+ {
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 72, 14, strlen("recursive"),
+ u"newNameNewMe"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 74, 24, strlen("recursive"),
+ u"newNameNewMe"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 74, 34, strlen("recursive"),
+ u"newNameNewMe"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 74, 51, strlen("recursive"),
+ u"newNameNewMe"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 74, 68, strlen("recursive"),
+ u"newNameNewMe"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 76, 20, strlen("recursive"),
+ u"newNameNewMe"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 79, 34, strlen("recursive"),
+ u"newNameNewMe"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 84, 27, strlen("recursive"),
+ u"newNameNewMe"_s),
+ },
+ {}
};
- QList<QQmlLSUtilsEdit> JSIdentifierSumRename{
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 8, 13, strlen("sum"),
- u"sumsumsum123"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 10, 13, strlen("sum"),
- u"sumsumsum123"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 10, 19, strlen("sum"),
- u"sumsumsum123"_s),
+ QQmlLSUtils::RenameUsages JSIdentifierSumRename{
+ {
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 8, 13, strlen("sum"),
+ u"sumsumsum123"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 10, 13, strlen("sum"),
+ u"sumsumsum123"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 10, 19, strlen("sum"),
+ u"sumsumsum123"_s),
+ },
+ {}
};
- QList<QQmlLSUtilsEdit> qmlSignalRename{
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 88, 12, strlen("helloSignal"),
- u"finalSignal"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 91, 9, strlen("helloSignal"),
- u"finalSignal"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 93, 13, strlen("helloSignal"),
- u"finalSignal"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 97, 17, strlen("helloSignal"),
- u"finalSignal"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 101, 9, strlen("helloSignal"),
- u"finalSignal"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 119, 5, strlen("onHelloSignal"),
- u"onFinalSignal"_s),
+ QQmlLSUtils::RenameUsages qmlSignalRename{
+ {
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 88, 12,
+ strlen("helloSignal"), u"finalSignal"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 91, 9, strlen("helloSignal"),
+ u"finalSignal"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 93, 13,
+ strlen("helloSignal"), u"finalSignal"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 97, 17,
+ strlen("helloSignal"), u"finalSignal"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 101, 9,
+ strlen("helloSignal"), u"finalSignal"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 119, 5,
+ strlen("onHelloSignal"), u"onFinalSignal"_s),
+ },
+ {}
};
- QList<QQmlLSUtilsEdit> helloPropertyRename{
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 17, 18, strlen("helloProperty"),
- u"freshPropertyName"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 24, 13, strlen("helloProperty"),
- u"freshPropertyName"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 24, 29, strlen("helloProperty"),
- u"freshPropertyName"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 65, 60, strlen("helloProperty"),
- u"freshPropertyName"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 151, 9, strlen("helloPropertyChanged"),
- u"freshPropertyNameChanged"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 153, 5,
- strlen("onHelloPropertyChanged"), u"onFreshPropertyNameChanged"_s),
- QQmlLSUtilsEdit::from(testFileNameFromAnotherFile, testFileFromAnotherFileContent, 12, 16,
- strlen("helloProperty"), u"freshPropertyName"_s),
+ QQmlLSUtils::RenameUsages helloPropertyRename{
+ {
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 17, 18,
+ strlen("helloProperty"), u"freshPropertyName"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 24, 13,
+ strlen("helloProperty"), u"freshPropertyName"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 24, 29,
+ strlen("helloProperty"), u"freshPropertyName"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 65, 60,
+ strlen("helloProperty"), u"freshPropertyName"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 151, 9,
+ strlen("helloPropertyChanged"),
+ u"freshPropertyNameChanged"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 153, 5,
+ strlen("onHelloPropertyChanged"),
+ u"onFreshPropertyNameChanged"_s),
+ QQmlLSUtils::Edit::from(testFileNameFromAnotherFile, testFileFromAnotherFileContent,
+ 12, 16, strlen("helloProperty"), u"freshPropertyName"_s),
+ },
+ {}
};
- QList<QQmlLSUtilsEdit> nestedComponentRename{
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 42, 15, strlen("NestedComponent"),
- u"SuperInlineComponent"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 61, 5, strlen("NestedComponent"),
- u"SuperInlineComponent"_s),
+ QQmlLSUtils::RenameUsages nestedComponentRename{
+ {
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 42, 15,
+ strlen("NestedComponent"), u"SuperInlineComponent"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 61, 5,
+ strlen("NestedComponent"), u"SuperInlineComponent"_s),
+ },
+ {}
};
- QList<QQmlLSUtilsEdit> myNestedIdRename{
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 62, 13, strlen("myNested"),
- u"freshNewIdForMyNested"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 65, 17, strlen("myNested"),
- u"freshNewIdForMyNested"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 66, 17, strlen("myNested"),
- u"freshNewIdForMyNested"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 67, 17, strlen("myNested"),
- u"freshNewIdForMyNested"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 68, 17, strlen("myNested"),
- u"freshNewIdForMyNested"_s),
- QQmlLSUtilsEdit::from(testFileName, testFileContent, 69, 17, strlen("myNested"),
- u"freshNewIdForMyNested"_s),
+ QQmlLSUtils::RenameUsages myNestedIdRename{
+ {
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 62, 13, strlen("myNested"),
+ u"freshNewIdForMyNested"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 65, 17, strlen("myNested"),
+ u"freshNewIdForMyNested"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 66, 17, strlen("myNested"),
+ u"freshNewIdForMyNested"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 67, 17, strlen("myNested"),
+ u"freshNewIdForMyNested"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 68, 17, strlen("myNested"),
+ u"freshNewIdForMyNested"_s),
+ QQmlLSUtils::Edit::from(testFileName, testFileContent, 69, 17, strlen("myNested"),
+ u"freshNewIdForMyNested"_s),
+ },
+ {}
};
- std::sort(methodFRename.begin(), methodFRename.end());
- std::sort(JSIdentifierSumRename.begin(), JSIdentifierSumRename.end());
- std::sort(qmlSignalRename.begin(), qmlSignalRename.end());
- std::sort(helloPropertyRename.begin(), helloPropertyRename.end());
- std::sort(helloPropertyRename.begin(), helloPropertyRename.end());
- std::sort(nestedComponentRename.begin(), nestedComponentRename.end());
- std::sort(myNestedIdRename.begin(), myNestedIdRename.end());
+ const QString renameFileQml = testFile("renaming/main.qml");
+ const QString renameFileQmlContent = readFileContent(renameFileQml);
+ const QQmlLSUtils::RenameUsages renameComponent1{
+ {
+ QQmlLSUtils::Edit::from(renameFileQml, renameFileQmlContent, 4, 5,
+ strlen("RenameMe"), u"FreshNewComponentName"_s),
+ },
+ {
+ { testFile("renaming/RenameMe.qml"),
+ testFile(u"renaming/FreshNewComponentName.qml"_s) },
+ }
+ };
+ const QQmlLSUtils::RenameUsages renameComponent2{
+ {
+ QQmlLSUtils::Edit::from(renameFileQml, renameFileQmlContent, 5, 5,
+ strlen("RenameMe2"), u"AnotherOneThankYou"_s),
+ },
+ {
+ { testFile("renaming/RenameMe2.ui.qml"),
+ testFile(u"renaming/AnotherOneThankYou.ui.qml"_s) },
+ }
+ };
+ const QQmlLSUtils::RenameUsages renameComponentNamedByQmldir{
+ {
+ QQmlLSUtils::Edit::from(renameFileQml, renameFileQmlContent, 6, 5,
+ strlen("HelloWorld"), u"AnotherOneThankYou"_s),
+ },
+ // make sure that the file itself does not get renamed
+ {}
+ };
const QString parserError = u"Invalid EcmaScript identifier!"_s;
@@ -1461,6 +1659,16 @@ void tst_qmlls_utils::renameUsages_data()
QTest::addRow("JSIdentifierStartsWithNumber")
<< testFileName << 67 << 13 << u"123"_s << noRenames << parserError;
+
+ QTest::addRow("renameQmlFile") << testFile(u"renaming/main.qml"_s) << 4 << 9
+ << u"FreshNewComponentName"_s << renameComponent1 << noError;
+
+ QTest::addRow("renameUiQmlFile") << testFile(u"renaming/main.qml"_s) << 5 << 9
+ << u"AnotherOneThankYou"_s << renameComponent2 << noError;
+
+ QTest::addRow("renameQmlFileRenamedByQmldir")
+ << testFile(u"renaming/main.qml"_s) << 6 << 8 << u"AnotherOneThankYou"_s
+ << renameComponentNamedByQmldir << noError;
}
void tst_qmlls_utils::renameUsages()
@@ -1471,10 +1679,15 @@ void tst_qmlls_utils::renameUsages()
QFETCH(int, line);
QFETCH(int, character);
QFETCH(QString, newName);
- QFETCH(QList<QQmlLSUtilsEdit>, expectedRenames);
+ QFETCH(QQmlLSUtils::RenameUsages, expectedRenames);
QFETCH(QString, expectedError);
- QVERIFY(std::is_sorted(expectedRenames.begin(), expectedRenames.end()));
+ {
+ const auto renameInFile = expectedRenames.renameInFile();
+ QVERIFY(std::is_sorted(renameInFile.constBegin(), renameInFile.constEnd()));
+ const auto renameInFilename = expectedRenames.renameInFilename();
+ QVERIFY(std::is_sorted(renameInFilename.begin(), renameInFilename.end()));
+ }
auto [env, file] = createEnvironmentAndLoadFile(filePath);
@@ -1505,21 +1718,29 @@ void tst_qmlls_utils::renameUsages()
if constexpr (enable_debug_output) {
if (edits != expectedRenames) {
qDebug() << "Got:\n";
- for (auto &x : edits) {
+ for (auto &x : edits.renameInFile()) {
qDebug() << x.replacement << x.location.filename << "("
<< x.location.sourceLocation.startLine << ", "
<< x.location.sourceLocation.startColumn << "), "
<< x.location.sourceLocation.offset << "+"
<< x.location.sourceLocation.length;
}
+ qDebug() << "with renames in filenames:";
+ for (auto &x : edits.renameInFilename()) {
+ qDebug() << x.oldFilename << "->" << x.newFilename;
+ }
qDebug() << "But expected: \n";
- for (auto &x : expectedRenames) {
+ for (auto &x : expectedRenames.renameInFile()) {
qDebug() << x.replacement << x.location.filename << "("
<< x.location.sourceLocation.startLine << ", "
<< x.location.sourceLocation.startColumn << "), "
<< x.location.sourceLocation.offset << "+"
<< x.location.sourceLocation.length;
}
+ qDebug() << "with renames in filenames:";
+ for (auto &x : expectedRenames.renameInFilename()) {
+ qDebug() << x.oldFilename << "->" << x.newFilename;
+ }
}
}
QCOMPARE(edits, expectedRenames);
@@ -1676,11 +1897,13 @@ void tst_qmlls_utils::resolveExpressionType_data()
// keep in mind that line and character are starting at 1!
QTest::addColumn<int>("line");
QTest::addColumn<int>("character");
- QTest::addColumn<QQmlLSUtilsResolveOptions>("resolveOption");
+ QTest::addColumn<QQmlLSUtils::ResolveOptions>("resolveOption");
QTest::addColumn<QString>("expectedFile");
// startline of the owners definition
QTest::addColumn<int>("expectedLine");
- QTest::addColumn<QQmlLSUtilsIdentifierType>("expectedType");
+ QTest::addColumn<QQmlLSUtils::IdentifierType>("expectedType");
+
+ using namespace QQmlLSUtils;
const int noLine = -1;
const QString noFile;
@@ -1828,10 +2051,10 @@ void tst_qmlls_utils::resolveExpressionType()
QFETCH(QString, filePath);
QFETCH(int, line);
QFETCH(int, character);
- QFETCH(QQmlLSUtilsResolveOptions, resolveOption);
+ QFETCH(QQmlLSUtils::ResolveOptions, resolveOption);
QFETCH(QString, expectedFile);
QFETCH(int, expectedLine);
- QFETCH(QQmlLSUtilsIdentifierType, expectedType);
+ QFETCH(QQmlLSUtils::IdentifierType, expectedType);
// they all start at 1.
Q_ASSERT(line > 0);
@@ -3930,97 +4153,4 @@ void tst_qmlls_utils::cmakeBuildCommand()
QCOMPARE(QQmlLSUtils::cmakeBuildCommand(path), expected);
}
-void tst_qmlls_utils::qdochtmlparser_data()
-{
- QTest::addColumn<QString>("filePath");
- QTest::addColumn<QDocHtmlExtractor::Element>("element");
- QTest::addColumn<QDocHtmlExtractor::ExtractionMode>("extractionMode");
- QTest::addColumn<QString>("expectedDocumentation");
-
- QTest::addRow("qml-object-type-extended-plaintext")
- << testFile("qdochtmlparser/qml-qtqml-qtobject.html")
- << QDocHtmlExtractor::Element{"QtObject", QDocHtmlExtractor::ElementType::QmlType}
- << QDocHtmlExtractor::ExtractionMode::Extended
- << R"(The QtObject type is a non-visual element which contains only the objectName property.
-It can be useful to create a QtObject if you need an extremely lightweight type to enclose a set of custom properties:
-
- import QtQuick
-
- Item {
- QtObject {
- id: attributes
- property string name
- property int size
- property variant attributes
- }
-
- Text { text: attributes.name }
- }
-
-It can also be useful for C++ integration, as it is just a plain QObject. See the QObject documentation for further details.)";
-
- QTest::addRow("qml-object-type-simplified-plaintext")
- << testFile("qdochtmlparser/qml-qtqml-qtobject.html")
- << QDocHtmlExtractor::Element{"QtObject", QDocHtmlExtractor::ElementType::QmlType}
- << QDocHtmlExtractor::ExtractionMode::Simplified
- << R"(A basic QML type.)";
-
- QTest::addRow("qml-property-simplified-plaintext")
- << testFile("qdochtmlparser/qml-qtqml-qtobject.html")
- << QDocHtmlExtractor::Element{"objectName",QDocHtmlExtractor::ElementType::QmlProperty}
- << QDocHtmlExtractor::ExtractionMode::Simplified
- << R"(This property holds the QObject::objectName for this specific object instance.)";
-
- QTest::addRow("qml-property-simplified-plaintext-from-Qt5")
- << testFile("qdochtmlparser/qml-qtqml-qtobject-qt-5.html") << QDocHtmlExtractor::Element{"objectName", QDocHtmlExtractor::ElementType::QmlProperty}
- << QDocHtmlExtractor::ExtractionMode::Simplified
- << R"(This property holds the QObject::objectName for this specific object instance.)";
-
- QTest::addRow("qml-property-simplified-plaintext")
- << testFile("qdochtmlparser/qml-qtquick-item.html") << QDocHtmlExtractor::Element{"width", QDocHtmlExtractor::ElementType::QmlProperty}
- << QDocHtmlExtractor::ExtractionMode::Simplified
- << R"(Defines the item's position and size. The default value is 0.)";
-
- QTest::addRow("qml-group-property-simplified-plaintext")
- << testFile("qdochtmlparser/qml-qtquick-item.html") << QDocHtmlExtractor::Element{"anchors.fill", QDocHtmlExtractor::ElementType::QmlProperty}
- << QDocHtmlExtractor::ExtractionMode::Simplified
- << R"(Anchors provide a way to position an item by specifying its relationship with other items.)";
- QTest::addRow("qml-functions")
- << testFile("qdochtmlparser/qml-qtquick-item.html") << QDocHtmlExtractor::Element{"mapFromGlobal", QDocHtmlExtractor::ElementType::QmlMethod}
- << QDocHtmlExtractor::ExtractionMode::Simplified
- << "Maps the point (x, y), which is in the global coordinate system, to the item's coordinate system,"
- " and returns a point matching the mapped coordinate.";
-
- QTest::addRow("qml-functions-list")
- << testFile("qdochtmlparser/qml-qtquick-item.html") << QDocHtmlExtractor::Element{"mapFromItem", QDocHtmlExtractor::ElementType::QmlMethod}
- << QDocHtmlExtractor::ExtractionMode::Simplified
- << "Maps the point (x, y) or rect (x, y, width, height), which is in item's coordinate system,"
- " to this item's coordinate system, and returns a point or rect matching the mapped coordinate.";
- QTest::addRow("qml-signal")
- << testFile("qdochtmlparser/qml-qtquick-mousearea.html") << QDocHtmlExtractor::Element{"pressAndHold", QDocHtmlExtractor::ElementType::QmlSignal}
- << QDocHtmlExtractor::ExtractionMode::Simplified
- << "This signal is emitted when there is a long press (currently 800ms). The mouse parameter provides information about the press, "
- "including the x and y position of the press, and which button is pressed.";
-}
-
-void tst_qmlls_utils::qdochtmlparser()
-{
- QFETCH(QString, filePath);
- QFETCH(QDocHtmlExtractor::Element, element);
- QFETCH(QDocHtmlExtractor::ExtractionMode, extractionMode);
- QFETCH(QString, expectedDocumentation);
-
- const auto htmlCode = [](const QString &testFileName) {
- QFile file(testFileName);
- if (file.open(QIODeviceBase::ReadOnly | QIODevice::Text))
- return QString::fromUtf8(file.readAll());
- return QString{};
- }(filePath);
-
-
- QDocHtmlExtractor extractor(htmlCode);
- const auto actual = extractor.extract(element, extractionMode);
- QCOMPARE(actual, expectedDocumentation);
-}
-
QTEST_MAIN(tst_qmlls_utils)
diff --git a/tests/auto/qmlls/utils/tst_qmlls_utils.h b/tests/auto/qmlls/utils/tst_qmlls_utils.h
index 51fa74dd0a..2f1ea19a2c 100644
--- a/tests/auto/qmlls/utils/tst_qmlls_utils.h
+++ b/tests/auto/qmlls/utils/tst_qmlls_utils.h
@@ -80,9 +80,6 @@ private slots:
void cmakeBuildCommand();
- void qdochtmlparser_data();
- void qdochtmlparser();
-
private:
using EnvironmentAndFile = std::tuple<QQmlJS::Dom::DomItem, QQmlJS::Dom::DomItem>;
diff --git a/tests/auto/quick/CMakeLists.txt b/tests/auto/quick/CMakeLists.txt
index 3ecf89f351..32a893defb 100644
--- a/tests/auto/quick/CMakeLists.txt
+++ b/tests/auto/quick/CMakeLists.txt
@@ -95,6 +95,7 @@ if(QT_FEATURE_private_tests)
add_subdirectory(qquickspritesequence)
add_subdirectory(qquickrhiitem)
add_subdirectory(rendernode)
+ add_subdirectory(platform)
if(QT_FEATURE_opengl)
add_subdirectory(qquickframebufferobject)
diff --git a/tests/auto/quick/doc/how-tos/how-to-qml/BLACKLIST b/tests/auto/quick/doc/how-tos/how-to-qml/BLACKLIST
new file mode 100644
index 0000000000..c878ca06be
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-qml/BLACKLIST
@@ -0,0 +1,5 @@
+# QTBUG-126222
+[activeFocusDebugging]
+macOS
+ubuntu-22.04
+
diff --git a/tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp b/tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp
index 66dcb208fc..9b750a59ef 100644
--- a/tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp
+++ b/tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp
@@ -60,6 +60,7 @@ void tst_HowToQml::activeFocusDebugging()
auto *window = qobject_cast<QQuickWindow*>(engine.rootObjects().at(0));
window->show();
+ window->requestActivate();
QTest::ignoreMessage(QtDebugMsg, QRegularExpression("activeFocusItem: .*\"ActiveFocusDebuggingMain\""));
QVERIFY(QTest::qWaitForWindowActive(window));
diff --git a/tests/auto/quick/platform/CMakeLists.txt b/tests/auto/quick/platform/CMakeLists.txt
new file mode 100644
index 0000000000..6a5f5760fc
--- /dev/null
+++ b/tests/auto/quick/platform/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(ANDROID)
+ add_subdirectory(android)
+endif()
diff --git a/tests/auto/quick/platform/android/CMakeLists.txt b/tests/auto/quick/platform/android/CMakeLists.txt
new file mode 100644
index 0000000000..d902be5aac
--- /dev/null
+++ b/tests/auto/quick/platform/android/CMakeLists.txt
@@ -0,0 +1,4 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+add_subdirectory(qtandroiditemmodel)
diff --git a/tests/auto/quick/platform/android/qtandroiditemmodel/CMakeLists.txt b/tests/auto/quick/platform/android/qtandroiditemmodel/CMakeLists.txt
new file mode 100644
index 0000000000..d8cdb763c0
--- /dev/null
+++ b/tests/auto/quick/platform/android/qtandroiditemmodel/CMakeLists.txt
@@ -0,0 +1,25 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qtandroiditemmodel Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qtandroiditemmodel LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_qtandroiditemmodel
+ SOURCES
+ tst_qtandroiditemmodel.cpp
+ LIBRARIES
+ Qt::Gui
+ Qt::Quick
+ Qt::QuickPrivate
+)
+
+set_property(TARGET tst_qtandroiditemmodel APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/testdata
+)
diff --git a/tests/auto/quick/platform/android/qtandroiditemmodel/testdata/src/org/qtproject/qt/android/tests/TestModel.java b/tests/auto/quick/platform/android/qtandroiditemmodel/testdata/src/org/qtproject/qt/android/tests/TestModel.java
new file mode 100644
index 0000000000..6bfb1dbc2f
--- /dev/null
+++ b/tests/auto/quick/platform/android/qtandroiditemmodel/testdata/src/org/qtproject/qt/android/tests/TestModel.java
@@ -0,0 +1,120 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+package org.qtproject.qt.android.tests;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.qtproject.qt.android.QtAbstractItemModel;
+import org.qtproject.qt.android.QtModelIndex;
+
+public class TestModel extends QtAbstractItemModel {
+ int m_rows = 0;
+ int m_cols = 0;
+
+ @Override
+ public int columnCount(QtModelIndex parent) {
+ return parent.isValid() ? 0 : m_cols;
+ }
+
+ @Override
+ public Object data(QtModelIndex index, int role) {
+ int r = index.row();
+ int c = index.column();
+ if (r < 0 || c < 0 || c > m_cols || r > m_rows)
+ return null;
+
+ switch (role) {
+ case 0:
+ return String.format("r%d/c%d", r, c);
+ case 1:
+ return new Boolean(((r + c) % 2) == 0);
+ case 2:
+ return new Integer((c << 8) + r);
+ case 3:
+ return new Double((r + 1.0) / (c + 1.0));
+ case 4:
+ return new Long((c << 8) * (r << 8));
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public QtModelIndex index(int row, int column, QtModelIndex parent) {
+ return hasIndex(row, column, parent) ? createIndex(row, column, 0) : new QtModelIndex();
+ }
+
+ @Override
+ public QtModelIndex parent(QtModelIndex qtModelIndex) {
+ return new QtModelIndex();
+ }
+
+ @Override
+ public int rowCount(QtModelIndex parent) {
+ return parent.isValid() ? 0 : m_rows;
+ }
+
+ @Override
+ public HashMap<Integer,String> roleNames(){
+ final HashMap<Integer,String> roles = new HashMap<Integer,String>();
+ roles.put(0, "stringRole");
+ roles.put(1, "booleanRole");
+ roles.put(2, "integerRole");
+ roles.put(3, "doubleRole");
+ roles.put(4, "longRole");
+ return roles;
+ }
+
+ @Override public boolean canFetchMore(QtModelIndex parent)
+ {
+ return !parent.isValid() && (m_rows < 30);
+ }
+
+ @Override public void fetchMore(QtModelIndex parent)
+ {
+ if (!canFetchMore(parent))
+ return;
+ int toAdd = Math.min(10, 30 - rowCount(parent));
+ beginInsertRows(new QtModelIndex(), m_rows, m_rows + toAdd - 1);
+ m_rows += toAdd;
+ endInsertRows();
+ }
+
+ public void addRow() {
+ beginInsertRows(new QtModelIndex(), m_rows, m_rows);
+ m_rows++;
+ endInsertRows();
+ }
+
+ public void removeRow() {
+ if (m_rows == 0)
+ return;
+ beginRemoveRows(new QtModelIndex(), 0, 0);
+ m_rows--;
+ endRemoveRows();
+ }
+
+ public void addCol() {
+ beginInsertColumns(new QtModelIndex(), m_cols, m_cols);
+ m_cols++;
+ endInsertColumns();
+ }
+
+ public void removeCol() {
+ if (m_cols == 0)
+ return;
+ beginRemoveColumns(new QtModelIndex(), 0, 0);
+ m_cols--;
+ endRemoveColumns();
+ }
+
+ public void reset() {
+ beginResetModel();
+ m_rows = 0;
+ m_cols = 0;
+ endResetModel();
+ }
+}
diff --git a/tests/auto/quick/platform/android/qtandroiditemmodel/tst_qtandroiditemmodel.cpp b/tests/auto/quick/platform/android/qtandroiditemmodel/tst_qtandroiditemmodel.cpp
new file mode 100644
index 0000000000..ae1971df01
--- /dev/null
+++ b/tests/auto/quick/platform/android/qtandroiditemmodel/tst_qtandroiditemmodel.cpp
@@ -0,0 +1,182 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QTest>
+
+#include <QtQuick/private/qandroiditemmodelproxy_p.h>
+#include <QtQuick/private/qandroidmodelindexproxy_p.h>
+#include <QtQuick/private/qandroidtypes_p.h>
+
+#include <QGuiApplication>
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qjnitypes.h>
+#include <QtCore/qstring.h>
+
+using namespace Qt::Literals;
+
+Q_DECLARE_JNI_CLASS(JTestModel, "org/qtproject/qt/android/tests/TestModel")
+
+class tst_QtAndroidItemModel : public QObject
+{
+ Q_OBJECT
+ JTestModel jModel;
+ QAbstractItemModel *qProxy;
+ void resetModel();
+
+private slots:
+ void initTestCase();
+ void cleanup();
+ void addRow();
+ void addColumn();
+ void removeRow();
+ void removeColumn();
+ void roleNames();
+ void fetchMore();
+ void hasIndex();
+ void data();
+};
+
+void tst_QtAndroidItemModel::initTestCase()
+{
+ QVERIFY(jModel.isValid());
+ qProxy = QAndroidItemModelProxy::createNativeProxy(jModel);
+ QVERIFY(qProxy);
+}
+
+void tst_QtAndroidItemModel::cleanup()
+{
+ resetModel();
+}
+
+void tst_QtAndroidItemModel::addRow()
+{
+ const int rowsBefore = qProxy->rowCount();
+ jModel.callMethod<void>("addRow");
+ QCOMPARE_EQ(qProxy->rowCount(), rowsBefore + 1);
+}
+
+void tst_QtAndroidItemModel::addColumn()
+{
+ const int columnsBefore = qProxy->columnCount();
+ jModel.callMethod<void>("addCol");
+ QCOMPARE_EQ(qProxy->columnCount(), columnsBefore + 1);
+}
+
+void tst_QtAndroidItemModel::removeRow()
+{
+ jModel.callMethod<void>("addRow");
+ jModel.callMethod<void>("addRow");
+ QCOMPARE_EQ(qProxy->rowCount(), 2);
+ jModel.callMethod<void>("removeRow");
+ QCOMPARE_EQ(qProxy->rowCount(), 1);
+ jModel.callMethod<void>("removeRow");
+ QCOMPARE_EQ(qProxy->rowCount(), 0);
+}
+
+void tst_QtAndroidItemModel::removeColumn()
+{
+ jModel.callMethod<void>("addCol");
+ jModel.callMethod<void>("addCol");
+ QCOMPARE_EQ(qProxy->columnCount(), 2);
+ jModel.callMethod<void>("removeCol");
+ QCOMPARE_EQ(qProxy->columnCount(), 1);
+ jModel.callMethod<void>("removeCol");
+ QCOMPARE_EQ(qProxy->columnCount(), 0);
+}
+
+void tst_QtAndroidItemModel::roleNames()
+{
+ const static QHash<int, QByteArray> expectedRoles = { { 0, "stringRole" },
+ { 1, "booleanRole" },
+ { 2, "integerRole" },
+ { 3, "doubleRole" },
+ { 4, "longRole" } };
+ QCOMPARE(qProxy->roleNames(), expectedRoles);
+}
+
+void tst_QtAndroidItemModel::fetchMore()
+{
+ // In the Java TestModel :
+ // canFetchMore() returns true when row count is less than 30
+ // fetchMore() adds 10 rows at most, or the remaining until row count is 30
+ QVERIFY(qProxy->canFetchMore(QModelIndex()));
+ qProxy->fetchMore(QModelIndex());
+ QCOMPARE_EQ(qProxy->rowCount(), 10);
+ QVERIFY(qProxy->canFetchMore(QModelIndex()));
+ qProxy->fetchMore(QModelIndex());
+ QCOMPARE_EQ(qProxy->rowCount(), 20);
+ jModel.callMethod<void>("addRow");
+ QVERIFY(qProxy->canFetchMore(QModelIndex()));
+ qProxy->fetchMore(QModelIndex());
+ QCOMPARE_EQ(qProxy->rowCount(), 30);
+ QVERIFY(!qProxy->canFetchMore(QModelIndex()));
+}
+
+void tst_QtAndroidItemModel::hasIndex()
+{
+ // fetchMore() adds 10 rows
+ qProxy->fetchMore(QModelIndex());
+ jModel.callMethod<void>("addCol");
+ jModel.callMethod<void>("addCol");
+
+ for (int r = 0; r < 10; ++r) {
+ for (int c = 0; c < 2; ++c) {
+ QVERIFY(qProxy->hasIndex(r, c));
+ }
+ }
+}
+
+void tst_QtAndroidItemModel::data()
+{
+ const static QHash<int, QMetaType::Type> roleToType = { { 0, QMetaType::QString },
+ { 1, QMetaType::Bool },
+ { 2, QMetaType::Int },
+ { 3, QMetaType::Double },
+ { 4, QMetaType::Long } };
+ QVERIFY(qProxy->canFetchMore(QModelIndex()));
+ qProxy->fetchMore(QModelIndex());
+ QCOMPARE_EQ(qProxy->rowCount(), 10);
+ jModel.callMethod<void>("addCol");
+ jModel.callMethod<void>("addCol");
+ jModel.callMethod<void>("addCol");
+
+ for (int r = 0; r < 10; ++r) {
+ for (int c = 0; c < 3; ++c) {
+ QModelIndex index = qProxy->index(r, c);
+ for (int role : roleToType.keys()) {
+ const QVariant data = qProxy->data(index, role);
+ QCOMPARE_EQ(data.typeId(), roleToType[role]);
+ switch (role) {
+ case 0:
+ QCOMPARE(data.toString(),
+ "r%1/c%2"_L1.arg(QString::number(r), QString::number(c)));
+ break;
+ case 1:
+ QCOMPARE(data.toBool(), ((r + c) % 2) == 0);
+ break;
+ case 2:
+ QCOMPARE(data.toInt(), (c << 8) + r);
+ break;
+ case 3:
+ QVERIFY(qFuzzyCompare(data.toDouble(), (1.0 + r) / (1.0 + c)));
+ break;
+ case 4:
+ QCOMPARE(data.toULongLong(), ((c << 8) * (r << 8)));
+ break;
+ }
+ }
+ }
+ }
+}
+
+void tst_QtAndroidItemModel::resetModel()
+{
+ jModel.callMethod<void>("reset");
+ QCOMPARE_EQ(qProxy->rowCount(), 0);
+ QCOMPARE_EQ(qProxy->columnCount(), 0);
+}
+
+#include "tst_qtandroiditemmodel.moc"
+
+QTEST_MAIN(tst_QtAndroidItemModel)
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST b/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST
index f5259a9e64..fd3d9d96b8 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST
@@ -24,4 +24,7 @@ android
android
[touchAndDragHandlerOnFlickable]
android
+# QTBUG-118063
+[nativeGesturePinchOnFlickableWithParentTapHandler]
+opensuse-leap
diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
index e164d89217..d2a9ea9997 100644
--- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
+++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
@@ -63,6 +63,7 @@ private slots:
void checkableTest();
void ignoredTest();
void passwordTest();
+ void announceTest();
};
tst_QQuickAccessible::tst_QQuickAccessible()
@@ -161,7 +162,7 @@ void tst_QQuickAccessible::quickAttachedProperties()
// Attaching to non-item
{
QObject parent;
- QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML QtObject: Accessible must be attached to an Item");
+ QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML QtObject: Accessible must be attached to an Item or an Action");
QQuickAccessibleAttached *attachedObj = new QQuickAccessibleAttached(&parent);
QCOMPARE(attachedObj->ignored(), false);
@@ -699,6 +700,25 @@ void tst_QQuickAccessible::passwordTest()
QTestAccessibility::clearEvents();
}
+void tst_QQuickAccessible::announceTest()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick\nItem {\n"
+ "Component.onCompleted: Accessible.announce('I am complete!')"
+ "}",
+ QUrl());
+ auto object = std::unique_ptr<QObject>(component.create());
+ QVERIFY(object != nullptr);
+
+ QAccessibleEvent createdEvent(object.get(), QAccessible::ObjectCreated);
+ QVERIFY_EVENT(&createdEvent);
+ QAccessibleAnnouncementEvent event(object.get(), QStringLiteral("I am complete!"));
+ QVERIFY_EVENT(&event);
+
+ QTestAccessibility::clearEvents();
+}
+
QTEST_MAIN(tst_QQuickAccessible)
#include "tst_qquickaccessible.moc"
diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
index 25c8559ed3..5ae25f7dfb 100644
--- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
+++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
@@ -1,28 +1,31 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-#include <QtTest/QtTest>
+
+#include <private/qanimationgroupjob_p.h>
+#include <private/qmlutils_p.h>
+
+#include <private/qqmllistmodel_p.h>
+#include <private/qqmltimer_p.h>
+
+#include <private/qquickanimation_p_p.h>
+#include <private/qquickanimatorjob_p.h>
+#include <private/qquickflickable_p.h>
+#include <private/qquickframeanimation_p.h>
+#include <private/qquickitem_p.h>
+#include <private/qquickitemanimation_p.h>
+#include <private/qquickpathinterpolator_p.h>
+#include <private/qquickrectangle_p.h>
+#include <private/qquicktransition_p.h>
+
+#include <QtQuick/qquickview.h>
+
+#include <QtTest/qtest.h>
+#include <QtTest/qsignalspy.h>
+
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
-#include <QtQuick/qquickview.h>
-#include <QtQml/private/qqmltimer_p.h>
-#include <QtQmlModels/private/qqmllistmodel_p.h>
-#include <QtQml/private/qanimationgroupjob_p.h>
-#include <QtQuick/private/qquickrectangle_p.h>
-#include <QtQuick/private/qquickitemanimation_p.h>
-#include <QtQuick/private/qquickitemanimation_p_p.h>
-#include <QtQuick/private/qquicktransition_p.h>
-#include <QtQuick/private/qquickanimation_p.h>
-#include <QtQuick/private/qquickanimatorjob_p.h>
-#include <QtQuick/private/qquickpathinterpolator_p.h>
-#include <QtQuick/private/qquickitem_p.h>
-#include <QtQuick/private/qquicklistview_p.h>
-#include <QtQuick/private/qquickframeanimation_p.h>
-#include <QEasingCurve>
-
-#include <limits.h>
-#include <math.h>
-
-#include <QtQuickTestUtils/private/qmlutils_p.h>
+
+#include <QtCore/qeasingcurve.h>
class tst_qquickanimations : public QQmlDataTest
{
@@ -101,6 +104,7 @@ private slots:
void restartAnimationGroupWhenDirty();
void restartNestedAnimationGroupWhenDirty();
void targetsDeletedNotRemoved();
+ void alwaysRunToEndSetFalseRestartBug();
};
#define QTIMED_COMPARE(lhs, rhs) do { \
@@ -2295,6 +2299,41 @@ void tst_qquickanimations::targetsDeletedNotRemoved()
}
}
+//QTBUG-125224
+void tst_qquickanimations::alwaysRunToEndSetFalseRestartBug()
+{
+ QQuickRectangle rect;
+ QQuickSequentialAnimation sequential;
+ QQuickPropertyAnimation beginAnim;
+ QQuickPropertyAnimation endAnim;
+
+ beginAnim.setTargetObject(&rect);
+ beginAnim.setProperty("x");
+ beginAnim.setTo(200);
+ beginAnim.setDuration(1000);
+
+ endAnim.setTargetObject(&rect);
+ endAnim.setProperty("x");
+ endAnim.setFrom(200);
+ endAnim.setDuration(1000);
+
+ beginAnim.setGroup(&sequential);
+ endAnim.setGroup(&sequential);
+
+ sequential.setLoops(-1);
+ sequential.setAlwaysRunToEnd(true);
+
+ QCOMPARE(sequential.loops(), -1);
+ QVERIFY(sequential.alwaysRunToEnd());
+ sequential.start();
+ sequential.stop();
+ sequential.setAlwaysRunToEnd(false);
+ sequential.start();
+ QCOMPARE(sequential.isRunning(), true);
+ sequential.stop();
+ QCOMPARE(sequential.isRunning(), false);
+}
+
QTEST_MAIN(tst_qquickanimations)
#include "tst_qquickanimations.moc"
diff --git a/tests/auto/quick/qquickapplication/BLACKLIST b/tests/auto/quick/qquickapplication/BLACKLIST
new file mode 100644
index 0000000000..d643caebdd
--- /dev/null
+++ b/tests/auto/quick/qquickapplication/BLACKLIST
@@ -0,0 +1,4 @@
+[state]
+opensuse-leap # QTBUG-122031
+[active]
+opensuse-leap # QTBUG-75215
diff --git a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
index 48b9b833d5..0c1fa42d2f 100644
--- a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
+++ b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
@@ -246,7 +246,7 @@ void tst_qquickapplication::styleHints()
{
// technically not in QQuickApplication, but testing anyway here
QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0; Item { property variant styleHints: Qt.styleHints }", QUrl::fromLocalFile(""));
+ component.setData("import QtQuick 2.0; Item { property variant styleHints: Application.styleHints }", QUrl::fromLocalFile(""));
QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
QVERIFY(item);
QQuickView view;
diff --git a/tests/auto/quick/qquickflickable/BLACKLIST b/tests/auto/quick/qquickflickable/BLACKLIST
index d35ddb9e3f..a481b96db5 100644
--- a/tests/auto/quick/qquickflickable/BLACKLIST
+++ b/tests/auto/quick/qquickflickable/BLACKLIST
@@ -8,7 +8,3 @@ macos-11
# QTBUG-118060
[ignoreNonLeftMouseButtons]
opensuse-leap
-
-# QTBUG-118063
-[nativeGesturePinchOnFlickableWithParentTapHandler]
-opensuse-leap
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index b003511356..e13a818cf8 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -1693,7 +1693,7 @@ void tst_qquickflickable::flickVelocity()
QTRY_VERIFY(flickable->verticalVelocity() < 0.0);
QTRY_COMPARE(flickable->verticalVelocity(), 0.0);
-#ifdef Q_OS_MAC
+#ifdef Q_OS_MACOS
QSKIP("boost doesn't work on OS X");
return;
#endif
diff --git a/tests/auto/quick/qquickimage/data/multiframeAsyncRetain.qml b/tests/auto/quick/qquickimage/data/multiframeAsyncRetain.qml
new file mode 100644
index 0000000000..fc0f135528
--- /dev/null
+++ b/tests/auto/quick/qquickimage/data/multiframeAsyncRetain.qml
@@ -0,0 +1,7 @@
+import QtQuick
+
+Image {
+ source: "multi.ico"
+ asynchronous: true
+ retainWhileLoading: true
+}
diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
index 427a45977f..078ac34ffa 100644
--- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp
+++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
@@ -135,41 +135,49 @@ void tst_qquickimage::imageSource_data()
QTest::addColumn<bool>("async");
QTest::addColumn<bool>("cache");
QTest::addColumn<QString>("error");
+ QTest::addColumn<bool>("retainWhileLoading");
- QTest::newRow("local") << testFileUrl("colors.png").toString() << 120.0 << 120.0 << false << false << true << "";
- QTest::newRow("local no cache") << testFileUrl("colors.png").toString() << 120.0 << 120.0 << false << false << false << "";
- QTest::newRow("local async") << testFileUrl("colors1.png").toString() << 120.0 << 120.0 << false << true << true << "";
+ QTest::newRow("local") << testFileUrl("colors.png").toString() << 120.0 << 120.0 << false << false << true << "" << false;
+ QTest::newRow("local no cache") << testFileUrl("colors.png").toString() << 120.0 << 120.0 << false << false << false << "" << false;
+ QTest::newRow("local async") << testFileUrl("colors1.png").toString() << 120.0 << 120.0 << false << true << true << "" << false;
+ QTest::newRow("local async retain") << testFileUrl("colors1.png").toString() << 120.0 << 120.0 << false << true << true << "" << true;
QTest::newRow("local not found") << testFileUrl("no-such-file.png").toString() << 0.0 << 0.0 << false
- << false << true << "<Unknown File>:2:1: QML Image: Cannot open: " + testFileUrl("no-such-file.png").toString();
+ << false << true << "<Unknown File>:2:1: QML Image: Cannot open: " + testFileUrl("no-such-file.png").toString() << false;
QTest::newRow("local async not found") << testFileUrl("no-such-file-1.png").toString() << 0.0 << 0.0 << false
- << true << true << "<Unknown File>:2:1: QML Image: Cannot open: " + testFileUrl("no-such-file-1.png").toString();
- QTest::newRow("remote") << "/colors.png" << 120.0 << 120.0 << true << false << true << "";
- QTest::newRow("remote redirected") << "/oldcolors.png" << 120.0 << 120.0 << true << false << false << "";
+ << true << true << "<Unknown File>:2:1: QML Image: Cannot open: " + testFileUrl("no-such-file-1.png").toString() << false;
+ QTest::newRow("local async retain not found") << testFileUrl("no-such-file-1.png").toString() << 0.0 << 0.0 << false
+ << true << true << "<Unknown File>:2:1: QML Image: Cannot open: " + testFileUrl("no-such-file-1.png").toString() << true;
+ QTest::newRow("remote") << "/colors.png" << 120.0 << 120.0 << true << false << true << "" << false;
+ QTest::newRow("remote retain") << "/colors.png" << 120.0 << 120.0 << true << false << true << "" << true;
+ QTest::newRow("remote redirected") << "/oldcolors.png" << 120.0 << 120.0 << true << false << false << "" << false;
if (QImageReader::supportedImageFormats().contains("svg"))
- QTest::newRow("remote svg") << "/heart.svg" << 595.0 << 841.0 << true << false << false << "";
+ QTest::newRow("remote svg") << "/heart.svg" << 595.0 << 841.0 << true << false << false << "" << false;
if (QImageReader::supportedImageFormats().contains("svgz"))
- QTest::newRow("remote svgz") << "/heart.svgz" << 595.0 << 841.0 << true << false << false << "";
+ QTest::newRow("remote svgz") << "/heart.svgz" << 595.0 << 841.0 << true << false << false << "" << false;
if (graphicsApi != QSGRendererInterface::Software) {
- QTest::newRow("texturefile pkm format") << testFileUrl("logo.pkm").toString() << 256.0 << 256.0 << false << false << true << "";
- QTest::newRow("texturefile ktx format") << testFileUrl("car.ktx").toString() << 146.0 << 80.0 << false << false << true << "";
- QTest::newRow("texturefile async") << testFileUrl("logo.pkm").toString() << 256.0 << 256.0 << false << true << true << "";
- QTest::newRow("texturefile remote") << "/logo.pkm" << 256.0 << 256.0 << true << false << true << "";
+ QTest::newRow("texturefile pkm format") << testFileUrl("logo.pkm").toString() << 256.0 << 256.0 << false << false << true << "" << false;
+ QTest::newRow("texturefile ktx format") << testFileUrl("car.ktx").toString() << 146.0 << 80.0 << false << false << true << "" << false;
+ QTest::newRow("texturefile async") << testFileUrl("logo.pkm").toString() << 256.0 << 256.0 << false << true << true << "" << false;
+ QTest::newRow("texturefile async retain") << testFileUrl("logo.pkm").toString() << 256.0 << 256.0 << false << true << true << "" << true;
+ QTest::newRow("texturefile remote") << "/logo.pkm" << 256.0 << 256.0 << true << false << true << "" << false;
+ QTest::newRow("texturefile remote retain") << "/logo.pkm" << 256.0 << 256.0 << true << false << true << "" << true;
}
QTest::newRow("remote not found") << "/no-such-file.png" << 0.0 << 0.0 << true
- << false << true << "<Unknown File>:2:1: QML Image: Error transferring {{ServerBaseUrl}}/no-such-file.png - server replied: Not found";
- QTest::newRow("extless") << testFileUrl("colors").toString() << 120.0 << 120.0 << false << false << true << "";
- QTest::newRow("extless no cache") << testFileUrl("colors").toString() << 120.0 << 120.0 << false << false << false << "";
- QTest::newRow("extless async") << testFileUrl("colors1").toString() << 120.0 << 120.0 << false << true << true << "";
+ << false << true << "<Unknown File>:2:1: QML Image: Error transferring {{ServerBaseUrl}}/no-such-file.png - server replied: Not found" << false;
+ QTest::newRow("extless") << testFileUrl("colors").toString() << 120.0 << 120.0 << false << false << true << "" << false;
+ QTest::newRow("extless no cache") << testFileUrl("colors").toString() << 120.0 << 120.0 << false << false << false << "" << false;
+ QTest::newRow("extless async") << testFileUrl("colors1").toString() << 120.0 << 120.0 << false << true << true << "" << false;
+ QTest::newRow("extless async retain") << testFileUrl("colors1").toString() << 120.0 << 120.0 << false << true << true << "" << true;
QTest::newRow("extless not found") << testFileUrl("no-such-file").toString() << 0.0 << 0.0 << false
- << false << true << "<Unknown File>:2:1: QML Image: Cannot open: " + testFileUrl("no-such-file").toString();
+ << false << true << "<Unknown File>:2:1: QML Image: Cannot open: " + testFileUrl("no-such-file").toString() << false;
// Test that texture file is preferred over image file, when supported.
// Since pattern.pkm has different size than pattern.png, these tests verify that the right file has been loaded
if (graphicsApi != QSGRendererInterface::Software) {
- QTest::newRow("extless prefer-tex") << testFileUrl("pattern").toString() << 64.0 << 64.0 << false << false << true << "";
- QTest::newRow("extless prefer-tex async") << testFileUrl("pattern").toString() << 64.0 << 64.0 << false << true << true << "";
+ QTest::newRow("extless prefer-tex") << testFileUrl("pattern").toString() << 64.0 << 64.0 << false << false << true << "" << false;
+ QTest::newRow("extless prefer-tex async") << testFileUrl("pattern").toString() << 64.0 << 64.0 << false << true << true << "" << false;
} else {
- QTest::newRow("extless ignore-tex") << testFileUrl("pattern").toString() << 200.0 << 200.0 << false << false << true << "";
- QTest::newRow("extless ignore-tex async") << testFileUrl("pattern").toString() << 200.0 << 200.0 << false << true << true << "";
+ QTest::newRow("extless ignore-tex") << testFileUrl("pattern").toString() << 200.0 << 200.0 << false << false << true << "" << false;
+ QTest::newRow("extless ignore-tex async") << testFileUrl("pattern").toString() << 200.0 << 200.0 << false << true << true << "" << false;
}
}
@@ -183,6 +191,12 @@ void tst_qquickimage::imageSource()
QFETCH(bool, async);
QFETCH(bool, cache);
QFETCH(QString, error);
+ QFETCH(bool, retainWhileLoading);
+
+#if !QT_CONFIG(qml_network)
+ if (remote)
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
TestHTTPServer server;
if (remote) {
@@ -196,9 +210,10 @@ void tst_qquickimage::imageSource()
if (!error.isEmpty())
QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
- QString componentStr = "import QtQuick 2.0\nImage { source: \"" + source + "\"; asynchronous: "
+ QString componentStr = "import QtQuick\nImage { source: \"" + source + "\"; asynchronous: "
+ (async ? QLatin1String("true") : QLatin1String("false")) + "; cache: "
- + (cache ? QLatin1String("true") : QLatin1String("false")) + " }";
+ + (cache ? QLatin1String("true") : QLatin1String("false")) + "; retainWhileLoading: "
+ + (retainWhileLoading ? QLatin1String("true") : QLatin1String("false")) + " }";
QQmlComponent component(&engine);
component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
@@ -209,6 +224,8 @@ void tst_qquickimage::imageSource()
else
QVERIFY(!obj->asynchronous());
+ QCOMPARE(obj->retainWhileLoading(), retainWhileLoading);
+
if (cache)
QVERIFY(obj->cache());
else
@@ -554,6 +571,10 @@ void tst_qquickimage::tiling_QTBUG_6716_data()
void tst_qquickimage::noLoading()
{
+#if !QT_CONFIG(qml_network)
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
qRegisterMetaType<QQuickImageBase::Status>();
TestHTTPServer server;
@@ -696,6 +717,10 @@ void tst_qquickimage::sourceSize_QTBUG_16389()
// QTBUG-15690
void tst_qquickimage::nullPixmapPaint()
{
+#if !QT_CONFIG(qml_network)
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
QScopedPointer<QQuickView> window(new QQuickView(nullptr));
window->setSource(testFileUrl("nullpixmap.qml"));
window->show();
@@ -718,6 +743,10 @@ void tst_qquickimage::nullPixmapPaint()
void tst_qquickimage::imageCrash_QTBUG_22125()
{
+#if !QT_CONFIG(qml_network)
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
TestHTTPServer server;
QVERIFY2(server.listen(), qPrintable(server.errorString()));
server.serveDirectory(dataDirectory(), TestHTTPServer::Delay);
@@ -830,6 +859,10 @@ void tst_qquickimage::sourceSizeChanges()
QTRY_COMPARE(sourceSizeSpy.size(), 3);
// Remote
+#if !QT_CONFIG(qml_network)
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
ctxt->setContextProperty("srcImage", server.url("/heart.png"));
QTRY_COMPARE(img->status(), QQuickImage::Ready);
QTRY_COMPARE(sourceSizeSpy.size(), 4);
@@ -963,6 +996,10 @@ void tst_qquickimage::progressAndStatusChanges()
QTRY_COMPARE(statusSpy.size(), 1);
// Loading remote file
+#if !QT_CONFIG(qml_network)
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
ctxt->setContextProperty("srcImage", server.url("/heart.png"));
QTRY_COMPARE(obj->status(), QQuickImage::Loading);
QTRY_COMPARE(obj->progress(), 0.0);
@@ -1208,6 +1245,7 @@ void tst_qquickimage::multiFrame_data()
QTest::addRow("default") << "multiframe.qml" << false;
QTest::addRow("async") << "multiframeAsync.qml" << true;
+ QTest::addRow("async retain") << "multiframeAsyncRetain.qml" << true;
}
void tst_qquickimage::multiFrame()
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
index e4cc434909..338070b730 100644
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
@@ -2622,7 +2622,7 @@ class TransformItemPrivate :public QQuickItemPrivate
protected:
Q_DECLARE_PUBLIC(TransformItem)
- bool transformChanged(QQuickItem *transformedItem) override
+ bool transformChanged(QQuickItem *) override
{
Q_Q(TransformItem);
q->transformChanged = true;
diff --git a/tests/auto/quick/qquickitem2/data/embedded_FocusScope.qml b/tests/auto/quick/qquickitem2/data/embedded_FocusScope.qml
new file mode 100644
index 0000000000..0d154f76e5
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/embedded_FocusScope.qml
@@ -0,0 +1,37 @@
+import QtQuick
+
+Rectangle {
+ width: 300
+ height: 300
+
+ FocusScope {
+ width: parent.width
+ height: parent.height
+ focus: true
+
+ Column {
+ anchors.fill: parent
+ anchors.rightMargin: 2
+ anchors.leftMargin: 2
+ anchors.topMargin: 10
+ spacing: 20
+ Rectangle {
+ objectName: "rect1"
+ width: parent.width
+ height: 30
+ border.width: 1
+ border.color: activeFocus ? "blue" : "black"
+ focusPolicy: Qt.TabFocus
+ }
+ Rectangle {
+ objectName: "rect2"
+ width: parent.width
+ height: 30
+ border.width: 1
+ border.color: activeFocus ? "blue" : "black"
+ focusPolicy: Qt.TabFocus
+ focus: true
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/data/mapCoordinatesWithWindows.qml b/tests/auto/quick/qquickitem2/data/mapCoordinatesWithWindows.qml
index 8218c5230a..98fc0e77af 100644
--- a/tests/auto/quick/qquickitem2/data/mapCoordinatesWithWindows.qml
+++ b/tests/auto/quick/qquickitem2/data/mapCoordinatesWithWindows.qml
@@ -17,19 +17,19 @@ QtObject {
color: "red"
}
- Window {
- objectName: "childWindow"
- parent: windowA
+ WindowContainer {
x: 100; y: 100
width: 100; height: 100
- visible: true
- color: "blue"
+ window: Window {
+ objectName: "childWindow"
+ color: "blue"
- Rectangle {
- objectName: "childItemInChildWindow"
- x: 30; y: 30
- width: 50; height: 50
- color: "orange"
+ Rectangle {
+ objectName: "childItemInChildWindow"
+ x: 30; y: 30
+ width: 50; height: 50
+ color: "orange"
+ }
}
}
}
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index 267be73ec9..56271ec3f2 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -140,6 +140,7 @@ private slots:
void focusInScopeChanges();
#ifdef QT_WIDGETS_LIB
+ void embeddedInWidgetsFocus_data();
void embeddedInWidgetsFocus();
#endif
@@ -4441,8 +4442,16 @@ void tst_QQuickItem::focusInScopeChanges()
}
#ifdef QT_WIDGETS_LIB
+void tst_QQuickItem::embeddedInWidgetsFocus_data()
+{
+ QTest::addColumn<QUrl>("source");
+ QTest::newRow("Embedded") << testFileUrl("embedded.qml");
+ QTest::newRow("Embedded Focus Scope") << testFileUrl("embedded_FocusScope.qml");
+}
+
void tst_QQuickItem::embeddedInWidgetsFocus()
{
+ QFETCH(QUrl, source);
QWidget root;
QVBoxLayout *layout = new QVBoxLayout(&root);
@@ -4450,7 +4459,7 @@ void tst_QQuickItem::embeddedInWidgetsFocus()
lineEdit1->setFocusPolicy(Qt::FocusPolicy::TabFocus);
QQuickView *quickView = new QQuickView;
- quickView->setSource(testFileUrl("embedded.qml"));
+ quickView->setSource(source);
QWidget *container = QWidget::createWindowContainer(quickView, &root);
container->setMinimumSize(quickView->size());
container->setFocusPolicy(Qt::TabFocus);
diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
index d31a0b0fb8..56198f0d2e 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
@@ -1513,6 +1513,44 @@ Item {
}
Component {
+ id: rearrangeInvalidatedChildInNestedLayout
+ ColumnLayout {
+ anchors.fill: parent
+ RowLayout {
+ spacing: 0
+ Text {
+ Layout.preferredWidth: 50
+ text: "Text Text Text"
+ wrapMode: Text.WordWrap
+ }
+ Rectangle {
+ color: "red";
+ Layout.preferredWidth: 50
+ Layout.preferredHeight: 20
+ }
+ Rectangle {
+ color: "green"
+ Layout.preferredHeight: 20
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ function test_rearrangeInvalidatedChildInNestedLayout() {
+ let layout = rearrangeInvalidatedChildInNestedLayout.createObject(container)
+ waitForRendering(layout)
+
+ let item1 = layout.children[0].children[0]
+ let item2 = layout.children[0].children[1]
+ let item3 = layout.children[0].children[2]
+
+ compare(item1.width, 50)
+ compare(item2.width, 50)
+ compare(item3.width, 100)
+ }
+
+ Component {
id: changeChildrenOfHiddenLayout_Component
RowLayout {
property int childCount: 1
diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST
index e4da77acba..0871e4e5c4 100644
--- a/tests/auto/quick/qquicklistview/BLACKLIST
+++ b/tests/auto/quick/qquicklistview/BLACKLIST
@@ -13,3 +13,7 @@ macos ci
android
[contentHeightWithDelayRemove]
android
+
+# QTBUG-123894
+[multipleTransitions]
+macos
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index 48171266de..3def877f00 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -7979,7 +7979,7 @@ void tst_QQuickListView::flickBeyondBounds()
// Flick view up beyond bounds
flick(window.data(), QPoint(10, 10), QPoint(10, -2000), 180);
-#ifdef Q_OS_MAC
+#ifdef Q_OS_MACOS
QSKIP("Disabled due to flaky behavior on CI system (QTBUG-44493)");
QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 0);
#endif
diff --git a/tests/auto/quick/qquicklistview2/data/nestedSnap.qml b/tests/auto/quick/qquicklistview2/data/nestedSnap.qml
new file mode 100644
index 0000000000..d7f064da01
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/nestedSnap.qml
@@ -0,0 +1,63 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+pragma ComponentBehavior: Bound
+
+import QtQuick
+
+ListView {
+ id: row
+
+ width: 300
+ height: 300
+
+ orientation: Qt.Horizontal
+ snapMode: ListView.SnapOneItem
+ highlightRangeMode: ListView.StrictlyEnforceRange
+
+ model: 3
+ delegate: ListView {
+ id: column
+ objectName: "vertical column " + index
+
+ required property int index
+
+ width: 300
+ height: 300
+
+ orientation: Qt.Vertical
+ snapMode: ListView.SnapOneItem
+ highlightRangeMode: ListView.StrictlyEnforceRange
+
+ model: 3
+ delegate: Rectangle {
+ id: cell
+
+ required property int index
+
+ width: 300
+ height: 300
+ color: "transparent"
+ border.color: "#000"
+ border.width: 5
+ radius: 15
+
+ Text {
+ anchors.centerIn: parent
+ text: `Row: ${cell.index}`
+ }
+ }
+
+ Text {
+ anchors.verticalCenterOffset: -height
+ anchors.centerIn: parent
+ horizontalAlignment: Text.AlignHCenter
+ text: `Column: ${column.index}\ncurrentIndex: ${column.currentIndex}`
+ }
+ }
+
+ Text {
+ x: 10; y: 10
+ text: `currentIndex: ${row.currentIndex}`
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/singletonModelLifetime.qml b/tests/auto/quick/qquicklistview2/data/singletonModelLifetime.qml
index f230786723..8f314a1795 100644
--- a/tests/auto/quick/qquicklistview2/data/singletonModelLifetime.qml
+++ b/tests/auto/quick/qquicklistview2/data/singletonModelLifetime.qml
@@ -1,6 +1,6 @@
import QtQuick 2.15
import QtQuick.Window 2.15
-import test 1.0
+import SingletonModelLifeTimeTest 1.0
Window {
id: root
diff --git a/tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp b/tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp
index bdac2112b6..96dd27e7d2 100644
--- a/tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp
+++ b/tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp
@@ -35,6 +35,7 @@ private slots:
void delegateModelRefresh();
void wheelSnap();
void wheelSnap_data();
+ void nestedWheelSnap();
void sectionsNoOverlap();
void metaSequenceAsModel();
@@ -583,7 +584,7 @@ void tst_QQuickListView2::singletonModelLifetime()
{
// this does not really test any functionality of listview, but we do not have a good way
// to unit test QQmlAdaptorModel in isolation.
- qmlRegisterSingletonType<SingletonModel>("test", 1, 0, "SingletonModel",
+ qmlRegisterSingletonType<SingletonModel>("SingletonModelLifeTimeTest", 1, 0, "SingletonModel",
[](QQmlEngine* , QJSEngine*) -> QObject* { return new SingletonModel; });
QQmlApplicationEngine engine(testFile("singletonModelLifetime.qml"));
@@ -870,6 +871,67 @@ void tst_QQuickListView2::wheelSnap_data()
<< 210.0;
}
+void tst_QQuickListView2::nestedWheelSnap()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("nestedSnap.qml")));
+
+ quint64 timestamp = 10;
+ auto sendWheelEvent = [&timestamp, &window](const QPoint &pixelDelta, Qt::ScrollPhase phase) {
+ const QPoint pos(100, 100);
+ QWheelEvent event(pos, window.mapToGlobal(pos), pixelDelta, pixelDelta, Qt::NoButton,
+ Qt::NoModifier, phase, false, Qt::MouseEventSynthesizedBySystem);
+ event.setAccepted(false);
+ event.setTimestamp(timestamp);
+ QGuiApplication::sendEvent(&window, &event);
+ timestamp += 50;
+ };
+
+ QQuickListView *outerListView = qobject_cast<QQuickListView *>(window.rootObject());
+ QTRY_VERIFY(outerListView);
+ QSignalSpy outerCurrentIndexSpy(outerListView, &QQuickListView::currentIndexChanged);
+ int movingAtIndex = -1;
+
+ // send horizontal pixel-delta wheel events with phases; confirm that ListView hits the next item boundary
+ sendWheelEvent({}, Qt::ScrollBegin);
+ for (int i = 1; i < 4; ++i) {
+ sendWheelEvent({-50, 0}, Qt::ScrollUpdate);
+ if (movingAtIndex < 0 && outerListView->isMoving())
+ movingAtIndex = i;
+ }
+ QVERIFY(outerListView->isDragging());
+ sendWheelEvent({}, Qt::ScrollEnd);
+ QCOMPARE(outerListView->isDragging(), false);
+ QTRY_COMPARE(outerListView->isMoving(), false); // wait until it stops
+ qCDebug(lcTests) << "outer got moving after" << movingAtIndex
+ << "horizontal events; stopped at" << outerListView->contentX() << outerListView->currentIndex();
+ QCOMPARE_GT(movingAtIndex, 0);
+ QCOMPARE(outerListView->contentX(), 300);
+ QCOMPARE(outerCurrentIndexSpy.size(), 1);
+
+ movingAtIndex = -1;
+ QQuickListView *innerListView = qobject_cast<QQuickListView *>(outerListView->currentItem());
+ QTRY_VERIFY(innerListView);
+ QSignalSpy innerCurrentIndexSpy(innerListView, &QQuickListView::currentIndexChanged);
+
+ // send vertical pixel-delta wheel events with phases; confirm that ListView hits the next item boundary
+ sendWheelEvent({}, Qt::ScrollBegin);
+ for (int i = 1; i < 4; ++i) {
+ sendWheelEvent({0, -50}, Qt::ScrollUpdate);
+ if (movingAtIndex < 0 && innerListView->isMoving())
+ movingAtIndex = i;
+ }
+ QVERIFY(innerListView->isDragging());
+ sendWheelEvent({}, Qt::ScrollEnd);
+ QCOMPARE(innerListView->isDragging(), false);
+ QTRY_COMPARE(innerListView->isMoving(), false); // wait until it stops
+ qCDebug(lcTests) << "inner got moving after" << movingAtIndex
+ << "vertical events; stopped at" << innerListView->contentY() << innerListView->currentIndex();
+ QCOMPARE_GT(movingAtIndex, 0);
+ QCOMPARE(innerListView->contentY(), 300);
+ QCOMPARE(innerCurrentIndexSpy.size(), 1);
+}
+
class FriendlyItemView : public QQuickItemView
{
friend class ItemViewAccessor;
diff --git a/tests/auto/quick/qquickpath/tst_qquickpath.cpp b/tests/auto/quick/qquickpath/tst_qquickpath.cpp
index 9fd4d9ec8a..7ed9ad3749 100644
--- a/tests/auto/quick/qquickpath/tst_qquickpath.cpp
+++ b/tests/auto/quick/qquickpath/tst_qquickpath.cpp
@@ -5,6 +5,7 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQuick/private/qquickpath_p.h>
+#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuickTestUtils/private/qmlutils_p.h>
@@ -21,6 +22,10 @@ private slots:
void closedCatmullRomCurve();
void svg();
void line();
+ void rectangle_data();
+ void rectangle();
+ void rectangleRadii();
+ void appendRemove();
private:
void arc(QSizeF scale);
@@ -29,6 +34,7 @@ private:
void closedCatmullRomCurve(QSizeF scale, const QVector<QPointF> &points);
void svg(QSizeF scale);
void line(QSizeF scale);
+ void rectangle(const QQuickPath *path, const QRectF &rect);
};
static void compare(const QPointF &point, const QSizeF &scale, int line, double x, double y)
@@ -318,6 +324,126 @@ void tst_QuickPath::line()
line(QSizeF(7.23,7.23));
}
+void tst_QuickPath::rectangle_data()
+{
+ QTest::addColumn<QByteArray>("pathqml");
+ QTest::addColumn<QRectF>("rect");
+
+ QTest::newRow("basic") << QByteArray("PathRectangle { width: 100; height: 100 }\n")
+ << QRectF(0, 0, 100, 100);
+
+ QTest::newRow("relative") << QByteArray("startX: -50; startY: -100\nPathRectangle {"
+ "relativeX: 100.2; relativeY: 200.3;"
+ "width: 10.5; height: 10.5 }\n")
+ << QRectF(50.2, 100.3, 10.5, 10.5);
+
+ QTest::newRow("stroke") << QByteArray("PathRectangle { x: 5; y: 10; width: 100; height: 100;"
+ "strokeAdjustment: 20 }\n")
+ << QRectF(5, 10, 100, 100).adjusted(10, 10, -10, -10);
+}
+
+void tst_QuickPath::rectangle(const QQuickPath *path, const QRectF &rect)
+{
+ QCOMPARE(path->pointAtPercent(0), rect.topLeft());
+ QCOMPARE(path->pointAtPercent(1), rect.topLeft());
+ QCOMPARE(path->pointAtPercent(1.0 / 8), QPointF(rect.center().x(), rect.top()));
+ QCOMPARE(path->pointAtPercent(3.0 / 8), QPointF(rect.right(), rect.center().y()));
+ QCOMPARE(path->pointAtPercent(5.0 / 8), QPointF(rect.center().x(), rect.bottom()));
+ QCOMPARE(path->pointAtPercent(7.0 / 8), QPointF(rect.left(), rect.center().y()));
+}
+
+void tst_QuickPath::rectangle()
+{
+ QFETCH(QByteArray, pathqml);
+ QFETCH(QRectF, rect);
+
+ QQmlEngine engine;
+ QQmlComponent c1(&engine);
+ c1.setData("import QtQuick\nPath {\n" + pathqml + "}", QUrl());
+ QScopedPointer<QObject> o1(c1.create());
+ QQuickPath *path = qobject_cast<QQuickPath *>(o1.data());
+ QVERIFY(path);
+ QCOMPARE(path->pointAtPercent(0), rect.topLeft());
+ QCOMPARE(path->pointAtPercent(1), rect.topLeft());
+ QCOMPARE(path->pointAtPercent(1.0 / 8), QPointF(rect.center().x(), rect.top()));
+ QCOMPARE(path->pointAtPercent(3.0 / 8), QPointF(rect.right(), rect.center().y()));
+ QCOMPARE(path->pointAtPercent(5.0 / 8), QPointF(rect.center().x(), rect.bottom()));
+ QCOMPARE(path->pointAtPercent(7.0 / 8), QPointF(rect.left(), rect.center().y()));
+}
+
+#define COMPARE_RADII(P, Q) \
+ QCOMPARE(P.radius(), Q->radius()); \
+ QCOMPARE(P.topLeftRadius(), Q->topLeftRadius()); \
+ QCOMPARE(P.topRightRadius(), Q->topRightRadius()); \
+ QCOMPARE(P.bottomLeftRadius(), Q->bottomLeftRadius()); \
+ QCOMPARE(P.bottomRightRadius(), Q->bottomRightRadius());
+
+void tst_QuickPath::rectangleRadii()
+{
+ // Test that the radius logic of PathRectangle is the same as Rectangle's
+ QQmlEngine engine;
+ QQmlComponent c1(&engine);
+ c1.setData("import QtQuick\n"
+ "Rectangle { x: 10; y: 20; width: 30; height: 40\n"
+ "}",
+ QUrl());
+ QScopedPointer<QObject> o1(c1.create());
+ QQuickRectangle *quickRectangle = qobject_cast<QQuickRectangle *>(o1.data());
+ QVERIFY(quickRectangle);
+ QQuickPathRectangle pathRectangle;
+ pathRectangle.setX(quickRectangle->x());
+ pathRectangle.setY(quickRectangle->y());
+ pathRectangle.setWidth(quickRectangle->width());
+ pathRectangle.setHeight(quickRectangle->height());
+ COMPARE_RADII(pathRectangle, quickRectangle);
+ pathRectangle.setRadius(5);
+ quickRectangle->setRadius(5);
+ COMPARE_RADII(pathRectangle, quickRectangle);
+ pathRectangle.setBottomLeftRadius(15);
+ quickRectangle->setBottomLeftRadius(15);
+ COMPARE_RADII(pathRectangle, quickRectangle);
+ pathRectangle.setRadius(-5);
+ quickRectangle->setRadius(-5);
+ COMPARE_RADII(pathRectangle, quickRectangle);
+ pathRectangle.setRadius(0);
+ quickRectangle->setRadius(0);
+ COMPARE_RADII(pathRectangle, quickRectangle);
+ pathRectangle.setTopLeftRadius(-7);
+ quickRectangle->setTopLeftRadius(-7);
+ COMPARE_RADII(pathRectangle, quickRectangle);
+ pathRectangle.setRadius(4);
+ quickRectangle->setRadius(4);
+ pathRectangle.resetBottomLeftRadius();
+ quickRectangle->resetBottomLeftRadius();
+ pathRectangle.setTopRightRadius(0);
+ quickRectangle->setTopRightRadius(0);
+ pathRectangle.setTopLeftRadius(200);
+ quickRectangle->setTopLeftRadius(200);
+ COMPARE_RADII(pathRectangle, quickRectangle);
+}
+
+void tst_QuickPath::appendRemove()
+{
+ QQuickPath *path = new QQuickPath();
+ QQmlListReference pathElements(path, "pathElements");
+ QSignalSpy changedSpy(path, SIGNAL(changed()));
+
+ QCOMPARE(pathElements.count(), 0);
+ QCOMPARE(changedSpy.count(), 0);
+
+ pathElements.append(new QQuickPathElement(path));
+ pathElements.append(new QQuickPathElement(path));
+ pathElements.append(new QQuickPathElement(path));
+
+ QCOMPARE(pathElements.count(), 3);
+ QCOMPARE(changedSpy.count(), 3);
+
+ pathElements.clear();
+
+ QCOMPARE(pathElements.count(), 0);
+ QCOMPARE(changedSpy.count(), 4);
+}
+
QTEST_MAIN(tst_QuickPath)
#include "tst_qquickpath.moc"
diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
index 1b06e0047b..703d6e053d 100644
--- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
+++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
@@ -1379,7 +1379,7 @@ void tst_QQuickPathView::package()
QQuickPathView *pathView = window->rootObject()->findChild<QQuickPathView*>("photoPathView");
QVERIFY(pathView);
-#ifdef Q_OS_MAC
+#ifdef Q_OS_MACOS
QSKIP("QTBUG-27170 view does not reliably receive polish without a running animation");
#endif
@@ -2943,11 +2943,11 @@ public:
m_values << 0 << 1 << 2 << 3 << 4;
}
- int rowCount(const QModelIndex &parent = QModelIndex()) const {
+ int rowCount(const QModelIndex &parent = QModelIndex()) const final {
Q_UNUSED(parent);
return m_values.count();
}
- QVariant data(const QModelIndex &index, int role) const {
+ QVariant data(const QModelIndex &index, int) const final {
if (index.row() < 0 || m_values.count() <= index.row())
return QVariant();
diff --git a/tests/auto/quick/qquickpixmapcache/data/slowLoading.qml b/tests/auto/quick/qquickpixmapcache/data/slowLoading.qml
new file mode 100644
index 0000000000..7ac98ae87b
--- /dev/null
+++ b/tests/auto/quick/qquickpixmapcache/data/slowLoading.qml
@@ -0,0 +1,13 @@
+import QtQuick
+import PixmapCacheTest
+
+DeviceLoadingImage {
+ id: root
+ width: 240
+ height: 240
+ sourceSize.width: width
+ sourceSize.height: height
+ source: "image://slow/200"
+ asynchronous: true
+ retainWhileLoading: true
+}
diff --git a/tests/auto/quick/qquickpixmapcache/deviceloadingimage.cpp b/tests/auto/quick/qquickpixmapcache/deviceloadingimage.cpp
index 72a956d1d2..bc7a3b4246 100644
--- a/tests/auto/quick/qquickpixmapcache/deviceloadingimage.cpp
+++ b/tests/auto/quick/qquickpixmapcache/deviceloadingimage.cpp
@@ -19,25 +19,24 @@ void DeviceLoadingImage::load()
Q_ASSERT(context);
QUrl resolved = context->resolvedUrl(d->url);
device = std::make_unique<QFile>(resolved.toLocalFile());
- d->pix.loadImageFromDevice(qmlEngine(this), device.get(), context->resolvedUrl(d->url),
+ const bool statusChange = (d->status != Loading);
+ if (statusChange)
+ d->status = Loading;
+ d->pendingPix->loadImageFromDevice(qmlEngine(this), device.get(), context->resolvedUrl(d->url),
d->sourceClipRect.toRect(), d->sourcesize * d->devicePixelRatio,
QQuickImageProviderOptions(), d->currentFrame, d->frameCount);
+ connectSuccess &= d->pendingPix->connectFinished(this, thisRequestFinished);
+ connectSuccess &= d->pendingPix->connectFinished(this, SLOT(onRequestFinished()));
+ qCDebug(lcTests) << "loading page" << d->currentFrame << "of" << d->frameCount
+ << "statuses" << d->currentPix->status() << d->pendingPix->status()
+ << "waiting?" << connectSuccess;
+ if (statusChange)
+ emit statusChanged(d->status);
+}
- qCDebug(lcTests) << "loading page" << d->currentFrame << "of" << d->frameCount << "status" << d->pix.status();
-
- switch (d->pix.status()) {
- case QQuickPixmap::Ready:
- pixmapChange();
- break;
- case QQuickPixmap::Loading:
- d->pix.connectFinished(this, thisRequestFinished);
- if (d->status != Loading) {
- d->status = Loading;
- emit statusChanged(d->status);
- }
- break;
- default:
- qCWarning(lcTests) << "unexpected status" << d->pix.status();
- break;
- }
+void DeviceLoadingImage::onRequestFinished()
+{
+ auto *d = static_cast<QQuickImagePrivate *>(QQuickImagePrivate::get(this));
+ qCDebug(lcTests) << "statuses" << d->currentPix->status() << d->pendingPix->status();
+ ++requestsFinished;
}
diff --git a/tests/auto/quick/qquickpixmapcache/deviceloadingimage.h b/tests/auto/quick/qquickpixmapcache/deviceloadingimage.h
index 062f51d16f..c00b456b94 100644
--- a/tests/auto/quick/qquickpixmapcache/deviceloadingimage.h
+++ b/tests/auto/quick/qquickpixmapcache/deviceloadingimage.h
@@ -15,5 +15,11 @@ public:
protected:
void load() override;
+protected slots:
+ void onRequestFinished();
+
+public:
std::unique_ptr<QFile> device;
+ bool connectSuccess = true;
+ int requestsFinished = 0;
};
diff --git a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
index fce9bba0c6..37d2fa39c9 100644
--- a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
+++ b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtTest/QtTest>
+#include <QtQuick/private/qquickimage_p_p.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
#include <QtQml/qqmlengine.h>
#include <QtQuick/qquickimageprovider.h>
@@ -18,18 +19,20 @@
#include <qfuture.h>
#endif
+#include "deviceloadingimage.h"
+
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
class SlowProvider : public QQuickImageProvider
{
public:
- SlowProvider() : QQuickImageProvider(Pixmap) {}
+ SlowProvider() : QQuickImageProvider(Image) {}
- QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize) override
+ QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize) override
{
const int row = id.toInt();
qCDebug(lcTests) << requestCount << QThread::currentThread() << "row" << row << requestedSize;
- QPixmap image(requestedSize);
+ QImage image(requestedSize, QImage::Format_RGB888);
QPainter painter(&image);
const QColor c(128, row % 8 * 32, 64);
painter.fillRect(0, 0, requestedSize.width(), requestedSize.height(), c);
@@ -73,6 +76,7 @@ private slots:
void dataLeak();
#endif
void slowDevice();
+ void slowDeviceInterrupted();
private:
QQmlEngine engine;
TestHTTPServer server;
@@ -140,6 +144,11 @@ void tst_qquickpixmapcache::single()
QFETCH(bool, exists);
QFETCH(bool, neterror);
+#if !QT_CONFIG(qml_network)
+ if (target.scheme() == "http")
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
QString expectedError;
if (neterror) {
expectedError = "Error transferring " + target.toString() + " - server replied: Not found";
@@ -228,6 +237,11 @@ void tst_qquickpixmapcache::parallel()
QFETCH(int, incache);
QFETCH(int, cancel);
+#if !QT_CONFIG(qml_network)
+ if (target1.scheme() == "http" || target2.scheme() == "http")
+ QSKIP("Skipping due to lack of QML network feature");
+#endif
+
QList<QUrl> targets;
targets << target1 << target2;
@@ -542,6 +556,8 @@ void tst_qquickpixmapcache::dataLeak()
*/
void tst_qquickpixmapcache::slowDevice()
{
+ QSKIP("Crashes: QTBUG-126047");
+
#ifdef QT_BUILD_INTERNAL
auto *provider = new SlowProvider;
engine.addImageProvider("slow", provider); // takes ownership
@@ -565,6 +581,44 @@ void tst_qquickpixmapcache::slowDevice()
#endif
}
+void tst_qquickpixmapcache::slowDeviceInterrupted()
+{
+#ifdef QT_BUILD_INTERNAL
+ auto *provider = new SlowProvider;
+ engine.addImageProvider("slow", provider); // takes ownership
+
+ const QColor secondExpectedColor(128, 50 % 8 * 32, 64);
+
+ {
+ QQuickView window(&engine, nullptr);
+ QVERIFY(QQuickTest::showView(window, testFileUrl("slowLoading.qml")));
+ DeviceLoadingImage *dlimg = qobject_cast<DeviceLoadingImage *>(window.rootObject());
+ QVERIFY(dlimg);
+ // the declared source: "image://slow/200" should take 200 ms to load
+ QTRY_COMPARE(dlimg->status(), QQuickImageBase::Loading);
+ QVERIFY(dlimg->connectSuccess);
+ dlimg->setSource(QUrl("image://slow/50"));
+ QTRY_COMPARE(dlimg->requestsFinished, 2);
+ QCOMPARE(provider->requestCount, 2);
+ QCOMPARE(dlimg->status(), QQuickImageBase::Ready);
+ auto *img_d = static_cast<QQuickImagePrivate *>(QQuickImagePrivate::get(dlimg));
+ QCOMPARE(img_d->currentPix->image().pixelColor({1, 1}), secondExpectedColor);
+ QCOMPARE(QQuickPixmapCache::instance()->m_cache.size(), 2);
+ // Unless CI paused at the wrong time for > 200 ms, we cancelled loading
+ // the first image and switched to the second, so QQuickImageBase::requestFinished()
+ // should have only called swap() once. But if this check ends up being flaky in CI,
+ // it can be be removed.
+ QCOMPARE(img_d->currentPix, &img_d->pix2);
+ } // window goes out of scope: all QQuickPixmapData instances should be eventually unreferenced
+
+ QTRY_COMPARE(QQuickPixmapCache::instance()->referencedCost(), 0);
+ const int leakedPixmaps = QQuickPixmapCache::instance()->destroyCache();
+ QCOMPARE_LE(leakedPixmaps, 0); // -1 if the cache is already destroyed
+#else
+ QSKIP("This test relies on private APIs that are only exported in developer-builds");
+#endif
+}
+
QT_END_NAMESPACE
QTEST_MAIN(tst_qquickpixmapcache)
diff --git a/tests/auto/quick/qquickshape/data/filltransform.qml b/tests/auto/quick/qquickshape/data/filltransform.qml
new file mode 100644
index 0000000000..4f83c04c43
--- /dev/null
+++ b/tests/auto/quick/qquickshape/data/filltransform.qml
@@ -0,0 +1,58 @@
+import QtQuick
+import QtQuick.Shapes
+import tst_qquickpathitem
+
+Rectangle {
+ width: 440
+ height: 220
+ color: "white"
+
+ Shape {
+ objectName: "shape1"
+ ShapePath {
+ id: path1
+ objectName: "path1"
+ fillGradient: RadialGradient {
+ centerX: path1.startX + 100
+ centerY: path1.startY + 100
+ centerRadius: 100
+ focalX: centerX
+ focalY: centerY
+ GradientStop { position: 0.0; color: "blue" }
+ GradientStop { position: 0.5; color: "cyan" }
+ GradientStop { position: 1.0; color: "blue" }
+ }
+
+ fillTransform: PlanarTransform.fromScale(2, 1);
+
+ startX: 10
+ startY: 10
+ PathLine { relativeX: 200; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: 200 }
+ PathLine { relativeX: -200; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: -200 }
+ }
+
+ ShapePath {
+ id: path2
+ objectName: "path2"
+ fillGradient: RadialGradient {
+ centerX: path2.startX + 100
+ centerY: path2.startY + 100
+ centerRadius: 100
+ focalX: centerX
+ focalY: centerY
+ GradientStop { position: 0.0; color: "blue" }
+ GradientStop { position: 0.5; color: "cyan" }
+ GradientStop { position: 1.0; color: "blue" }
+ }
+
+ startX: 220 + 10
+ startY: 10
+ PathLine { relativeX: 200; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: 200 }
+ PathLine { relativeX: -200; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: -200 }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
index f846cc4e4f..707e0037f5 100644
--- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp
+++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
@@ -62,6 +62,7 @@ private slots:
void multilineDataTypes_data();
void multilineDataTypes();
void multilineStronglyTyped();
+ void fillTransform();
private:
QVector<QPolygonF> m_lowPolyLogo;
@@ -247,6 +248,8 @@ void tst_QQuickShape::changeSignals()
QCOMPARE(vpChangeSpy.size(), 15);
qobject_cast<QQuickGradientStop *>(stopList.at(1))->setColor(Qt::black);
QCOMPARE(vpChangeSpy.size(), 16);
+ vp->setFillTransform(QMatrix4x4(QTransform::fromScale(3, 0.14)));
+ QCOMPARE(vpChangeSpy.size(), 17);
}
void tst_QQuickShape::render()
@@ -674,6 +677,40 @@ void tst_QQuickShape::multilineStronglyTyped()
}
}
+void tst_QQuickShape::fillTransform()
+{
+ QScopedPointer<QQuickView> window(createView());
+
+ window->setSource(testFileUrl("filltransform.qml"));
+ qApp->processEvents();
+
+ QQuickShape *obj = findItem<QQuickShape>(window->rootObject(), "shape1");
+ QVERIFY(obj != nullptr);
+ QQmlListReference list(obj, "data");
+ QCOMPARE(list.count(), 2);
+
+ QQuickShapePath *p1 = qobject_cast<QQuickShapePath *>(list.at(0));
+ QVERIFY(p1 != nullptr);
+ QVERIFY(p1->objectName() == "path1");
+ QVERIFY(p1->fillTransform() == QMatrix4x4(2,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1));
+
+ QQuickShapePath *p2 = qobject_cast<QQuickShapePath *>(list.at(1));
+ QVERIFY(p2 != nullptr);
+ QVERIFY(p2->objectName() == "path2");
+ QVERIFY(p2->fillTransform().isIdentity());
+
+ QMatrix4x4 xf(QTransform::fromTranslate(-36, 0).shear(0.35, 0));
+ p1->setFillTransform(xf);
+ QVERIFY(p1->fillTransform() == xf);
+
+ QVERIFY(p2->fillTransform().isIdentity());
+ p2->setFillTransform(xf);
+ QVERIFY(p2->fillTransform() == xf);
+
+ p1->setFillTransform(QMatrix4x4{});
+ QVERIFY(p1->fillTransform().isIdentity());
+}
+
QTEST_MAIN(tst_QQuickShape)
#include "tst_qquickshape.moc"
diff --git a/tests/auto/quick/qquickstates/data/anchorRewindBug3.qml b/tests/auto/quick/qquickstates/data/anchorRewindBug3.qml
new file mode 100644
index 0000000000..6d829be363
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/anchorRewindBug3.qml
@@ -0,0 +1,38 @@
+import QtQuick 2.0
+
+Rectangle {
+ id: root
+ width: 100; height: 100
+
+ Rectangle {
+ id: rectangle
+ objectName: "inner"
+ color: "green"
+ // Width and height end up to be 50
+ // after root Component.onCompleted
+ width: 75
+ height: 75
+ anchors.top: root.top
+ anchors.left: root.left
+ }
+
+ // Start with anchored state
+ state: "anchored"
+ states: [
+ State {
+ name: "anchored"
+ AnchorChanges {
+ target: rectangle
+ anchors.top: undefined
+ anchors.left: undefined
+ anchors.right: root.right
+ anchors.bottom: root.bottom
+ }
+ }
+ ]
+
+ Component.onCompleted: {
+ rectangle.width = 50
+ rectangle.height = 50
+ }
+}
diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
index 3bdbe29d1e..745837e2a3 100644
--- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp
+++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
@@ -154,6 +154,7 @@ private slots:
void anchorChangesCrash();
void anchorRewindBug();
void anchorRewindBug2();
+ void anchorRewind_keepsSize_whenStateResetsDefaultAnchors();
void script();
void restoreEntryValues();
void explicitChanges();
@@ -1087,6 +1088,30 @@ void tst_qquickstates::anchorRewindBug2()
QCOMPARE(mover->width(), qreal(50.0));
}
+// QTBUG-126057
+void tst_qquickstates::anchorRewind_keepsSize_whenStateResetsDefaultAnchors()
+{
+ // Arrange
+ QQmlEngine engine;
+
+ // NOTE: Contains two nested rectangles, inner is by default anchored to the top left corner of
+ // its parent. A state is initially "anchored" which removes the default anchoring and anchors
+ // the inner rectangle to the bottom right corner of the parent. The size of the inner rectangle
+ // is assigned to 50x50 on Component.onCompleted of outer rectangle.
+ QQmlComponent rectComponent(&engine, testFileUrl("anchorRewindBug3.qml"));
+ QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle*>(rectComponent.create()));
+ QVERIFY(rect != nullptr);
+ QQuickRectangle *mover = rect->findChild<QQuickRectangle*>("inner");
+ QVERIFY(mover != nullptr);
+
+ // Act
+ QQuickItemPrivate::get(rect.get())->setState("");
+
+ // Assert
+ QCOMPARE(mover->width(), qreal(50.0));
+ QCOMPARE(mover->height(), qreal(50.0));
+}
+
void tst_qquickstates::script()
{
QQmlEngine engine;
diff --git a/tests/auto/quick/qquicktableview/data/reordertableview.qml b/tests/auto/quick/qquicktableview/data/reordertableview.qml
new file mode 100644
index 0000000000..704126180f
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/reordertableview.qml
@@ -0,0 +1,52 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+ property real delegateWidth: 100
+ property real delegateHeight: 50
+ property Component delegate: tableViewDelegate
+ property bool delegateParentSetBeforeCompleted: false
+
+ TableView {
+ id: tableView
+ width: 600
+ height: 400
+ anchors.margins: 1
+ clip: true
+ delegate: tableViewDelegate
+ columnSpacing: 1
+ rowSpacing: 1
+ animate: false
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ required property int column
+ required property int row
+ objectName: "tableViewDelegate" + column + row
+ implicitWidth: delegateWidth
+ implicitHeight: delegateHeight
+ color: "lightgray"
+ border.width: 1
+
+ property string modelDataBinding: modelData
+
+ Text {
+ anchors.centerIn: parent
+ text: modelData
+ }
+
+ Component.onCompleted: {
+ delegateParentSetBeforeCompleted = parent != null;
+ }
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index bb425b5a6f..56dee4b585 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -279,6 +279,13 @@ private slots:
void checkScroll_data();
void checkScroll();
void checkRebuildJsModel();
+
+ // Row and column reordering
+ void checkVisualRowColumnAfterReorder();
+ void checkColumnRowSizeAfterReorder();
+ void checkCellModelIdxAfterReorder();
+ void checkEditAfterReorder();
+ void checkSelectionAfterReorder();
};
tst_QQuickTableView::tst_QQuickTableView()
@@ -4868,23 +4875,23 @@ void tst_QQuickTableView::testSelectableScrollTowardsPos()
const QPointF bottomLeft(-100, tableView->height() + 100);
const QPointF bottomRight(tableView->width() + 100, tableView->height() + 100);
- tableViewPrivate->scrollTowardsSelectionPoint(topRight, step);
+ tableViewPrivate->scrollTowardsPoint(topRight, step);
QCOMPARE(tableView->contentX(), step.width());
QCOMPARE(tableView->contentY(), 0);
- tableViewPrivate->scrollTowardsSelectionPoint(bottomRight, step);
+ tableViewPrivate->scrollTowardsPoint(bottomRight, step);
QCOMPARE(tableView->contentX(), step.width() * 2);
QCOMPARE(tableView->contentY(), step.height());
- tableViewPrivate->scrollTowardsSelectionPoint(bottomLeft, step);
+ tableViewPrivate->scrollTowardsPoint(bottomLeft, step);
QCOMPARE(tableView->contentX(), step.width());
QCOMPARE(tableView->contentY(), step.height() * 2);
- tableViewPrivate->scrollTowardsSelectionPoint(topLeft, step);
+ tableViewPrivate->scrollTowardsPoint(topLeft, step);
QCOMPARE(tableView->contentX(), 0);
QCOMPARE(tableView->contentY(), step.height());
- tableViewPrivate->scrollTowardsSelectionPoint(topLeft, step);
+ tableViewPrivate->scrollTowardsPoint(topLeft, step);
QCOMPARE(tableView->contentX(), 0);
QCOMPARE(tableView->contentY(), 0);
}
@@ -7548,6 +7555,236 @@ void tst_QQuickTableView::checkRebuildJsModel()
QCOMPARE(tableView->property(modelUpdated).toInt(), 1);
}
+void tst_QQuickTableView::checkVisualRowColumnAfterReorder()
+{
+ LOAD_TABLEVIEW("reordertableview.qml"); // gives us 'tableView' variable
+ auto model = TestModelAsVariant(3, 3);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ QSignalSpy columnMovedSpy(tableView, &QQuickTableView::columnMoved);
+ QSignalSpy rowMovedSpy(tableView, &QQuickTableView::rowMoved);
+
+ // Move row and column
+ tableView->moveColumn(0, 2);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(columnMovedSpy.size(), 3);
+
+ tableView->moveRow(1, 0);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(rowMovedSpy.size(), 2);
+
+ QVariantList firstColumnVar = columnMovedSpy.takeFirst();
+ QCOMPARE(firstColumnVar.at(0), 0); // Logical index
+ QCOMPARE(firstColumnVar.at(1), 0); // Old visual index
+ QCOMPARE(firstColumnVar.at(2), 2); // New visual index
+
+ QVariantList firstRowVar = rowMovedSpy.takeFirst();
+ QCOMPARE(firstRowVar.at(0), 0); // Logical index
+ QCOMPARE(firstRowVar.at(1), 0); // Old visual index
+ QCOMPARE(firstRowVar.at(2), 1); // New visual index
+}
+
+void tst_QQuickTableView::checkColumnRowSizeAfterReorder()
+{
+ LOAD_TABLEVIEW("reordertableview.qml"); // gives us 'tableView' variable
+ auto model = TestModelAsVariant(3, 3);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ const QSignalSpy columMovedSpy(tableView, &QQuickTableView::columnMoved);
+ const QSignalSpy rowMovedSpy(tableView, &QQuickTableView::rowMoved);
+
+ for (int index = 0, minSize = 10; index < tableView->columns(); index++, minSize+=10) {
+ tableView->setColumnWidth(index, minSize);
+ tableView->setRowHeight(index, minSize);
+ }
+ WAIT_UNTIL_POLISHED;
+
+ // Move row and column
+ tableView->moveColumn(0, 2);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(columMovedSpy.size(), 3);
+
+ tableView->moveRow(0, 2);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(rowMovedSpy.size(), 3);
+
+ QCOMPARE(tableView->columnWidth(0), 20);
+ QCOMPARE(tableView->columnWidth(1), 30);
+ QCOMPARE(tableView->columnWidth(2), 10);
+
+ QCOMPARE(tableView->rowHeight(0), 20);
+ QCOMPARE(tableView->rowHeight(1), 30);
+ QCOMPARE(tableView->rowHeight(2), 10);
+}
+
+void tst_QQuickTableView::checkCellModelIdxAfterReorder()
+{
+ LOAD_TABLEVIEW("reordertableview.qml"); // gives us 'tableView' variable
+ auto model = TestModelAsVariant(3, 3);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ const QSignalSpy columnMovedSpy(tableView, &QQuickTableView::columnMoved);
+ const QSignalSpy rowMovedSpy(tableView, &QQuickTableView::rowMoved);
+
+ const QSharedPointer<TestModel> testModel = model.value<QSharedPointer<TestModel>>();
+ const QString objNameItem21(tableView->itemAtIndex(testModel->index(2, 1))->objectName());
+ const QString objNameItem00(tableView->itemAtIndex(testModel->index(0 ,0))->objectName());
+ const QString objNameItem11(tableView->itemAtIndex(testModel->index(1 ,1))->objectName());
+
+ // Move row and column
+ tableView->moveColumn(0, 2);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(columnMovedSpy.size(), 3);
+
+ tableView->moveRow(1, 0);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(rowMovedSpy.size(), 2);
+
+ // Check model index - index()
+ QModelIndex modelIndex = tableView->index(0, 0);
+ QCOMPARE(modelIndex.column(), 1);
+ QCOMPARE(modelIndex.row(), 1);
+
+ modelIndex = tableView->index(1, 1);
+ QCOMPARE(modelIndex.column(), 2);
+ QCOMPARE(modelIndex.row(), 0);
+
+ modelIndex = tableView->index(2, 2);
+ QCOMPARE(modelIndex.column(), 0);
+ QCOMPARE(modelIndex.row(), 2);
+
+ // Check cell index - cellAtIndex()
+ {
+ QPoint cell = tableView->cellAtIndex(testModel->index(0, 0));
+ QCOMPARE(cell.x(), 2);
+ QCOMPARE(cell.y(), 1);
+ }
+
+ // Check column and row index - columnAtIndex(), rowAtIndex()
+ {
+ int columnIndex = tableView->columnAtIndex(testModel->index(0, 0));
+ int rowIndex = tableView->rowAtIndex(testModel->index(0, 0));
+ QCOMPARE(columnIndex, 2);
+ QCOMPARE(rowIndex, 1);
+ }
+
+ // Check item - itemAtIndex()
+ // Item at index provides the item that is mapped to that model index
+ // and it shouldn't be confused with cell index
+ {
+ QQuickItem *item = tableView->itemAtIndex(testModel->index(0 ,0));
+ QCOMPARE(objNameItem00, item->objectName());
+ }
+
+ // Check item at cell localtion 0, 0 - itemAtCell()
+ {
+ QQuickItem *item = tableView->itemAtCell(QPoint(0, 0));
+ QCOMPARE(objNameItem11, item->objectName());
+ }
+}
+
+void tst_QQuickTableView::checkEditAfterReorder()
+{
+ LOAD_TABLEVIEW("editdelegate.qml"); // gives us 'tableView' variable
+ auto model = TestModelAsVariant(3, 3);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ const QSignalSpy columnMovedSpy(tableView, &QQuickTableView::columnMoved);
+ const QSignalSpy rowMovedSpy(tableView, &QQuickTableView::rowMoved);
+
+ // Move row and column
+ tableView->moveColumn(0, 1);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(columnMovedSpy.size(), 2);
+
+ tableView->moveRow(0, 1);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(rowMovedSpy.size(), 2);
+
+ // Edit model index (0, 0)
+ const QSharedPointer<TestModel> testModel = model.value<QSharedPointer<TestModel>>();
+ const auto cellItem1 = tableView->itemAtCell(QPoint(0, 0));
+ QCOMPARE(cellItem1->property("editing").toBool(), false);
+
+ tableView->edit(testModel->index(1, 1));
+ QCOMPARE(cellItem1->property("editing").toBool(), true);
+
+ // Close the editor
+ tableView->closeEditor();
+ QCOMPARE(cellItem1->property("editing").toBool(), false);
+}
+
+void tst_QQuickTableView::checkSelectionAfterReorder()
+{
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(10, 10);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(selectionModel.hasSelection(), false);
+ QCOMPARE(tableView->selectionBehavior(), QQuickTableView::SelectCells);
+
+ const QSignalSpy columnMovedSpy(tableView, &QQuickTableView::columnMoved);
+ tableView->moveColumn(0, 2);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(columnMovedSpy.size(), 3);
+
+ const QPoint endCellDist(1, 1);
+ const QPoint startCell(0, 0);
+ const QPoint endCell = startCell + endCellDist;
+
+ const QQuickItem *startItem = tableView->itemAtCell(startCell);
+ const QQuickItem *endItem = tableView->itemAtCell(endCell);
+ QVERIFY(startItem);
+ QVERIFY(endItem);
+
+ const QPointF startPos(startItem->x(), startItem->y());
+ const QPointF endPos(endItem->x(), endItem->y());
+
+ QVERIFY(tableViewPrivate->startSelection(startPos, Qt::NoModifier));
+ tableViewPrivate->setSelectionStartPos(startPos);
+ tableViewPrivate->setSelectionEndPos(endPos);
+
+ QCOMPARE(selectionModel.hasSelection(), true);
+
+ const int x1 = qMin(startCell.x(), endCell.x());
+ const int x2 = qMax(startCell.x(), endCell.x());
+ const int y1 = qMin(startCell.y(), endCell.y());
+ const int y2 = qMax(startCell.y(), endCell.y());
+
+ for (int x = x1; x <= x2; ++x) {
+ for (int y = y1; y <= y2; ++y) {
+ const auto index = tableView->index(y, x);
+ QVERIFY(selectionModel.isSelected(index));
+ }
+ }
+
+ const int expectedCount = (x2 - x1 + 1) * (y2 - y1 + 1);
+ const int actualCount = selectionModel.selectedIndexes().size();
+ QCOMPARE(actualCount, expectedCount);
+
+ // The column which has been moved shouldn't have the selected
+ // bit enabled
+ for (int index = 0; index < model.rowCount(); index++)
+ QCOMPARE(selectionModel.isSelected(model.index(index, 0)), false);
+
+ tableViewPrivate->clearSelection();
+ QCOMPARE(selectionModel.hasSelection(), false);
+}
+
QTEST_MAIN(tst_QQuickTableView)
#include "tst_qquicktableview.moc"
diff --git a/tests/auto/quick/qquicktext/BLACKLIST b/tests/auto/quick/qquicktext/BLACKLIST
index a4e9c44eab..46936293ca 100644
--- a/tests/auto/quick/qquicktext/BLACKLIST
+++ b/tests/auto/quick/qquicktext/BLACKLIST
@@ -3,6 +3,7 @@ opensuse-42.1
[contentSize]
windows gcc
msvc-2019
+msvc-2022
[hAlignVisual]
sles
# QTQAINFRA-4127
diff --git a/tests/auto/quick/qquicktextdocument/data/initialText.qml b/tests/auto/quick/qquicktextdocument/data/initialText.qml
new file mode 100644
index 0000000000..be9280f952
--- /dev/null
+++ b/tests/auto/quick/qquicktextdocument/data/initialText.qml
@@ -0,0 +1,16 @@
+import QtQuick
+
+TextEdit {
+ id: te
+ property int sourceChangeCount: 0
+ property int modifiedChangeCount: 0
+ property var statusHistory: []
+
+ width: 320; height: 240
+ text: "Hello Qt"
+ focus: true
+
+ textDocument.onSourceChanged: ++te.sourceChangeCount
+ textDocument.onModifiedChanged: ++te.modifiedChangeCount
+ textDocument.onStatusChanged: te.statusHistory.push(textDocument.status)
+}
diff --git a/tests/auto/quick/qquicktextdocument/data/text.qml b/tests/auto/quick/qquicktextdocument/data/text.qml
index 9544471114..d1b9ee7203 100644
--- a/tests/auto/quick/qquicktextdocument/data/text.qml
+++ b/tests/auto/quick/qquicktextdocument/data/text.qml
@@ -6,6 +6,7 @@ TextEdit {
property int modifiedChangeCount: 0
property var statusHistory: []
+ width: 320; height: 240
text: "" // this is not a document modification
textDocument.onSourceChanged: ++te.sourceChangeCount
diff --git a/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp b/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp
index 535f20e7bb..e8c9f09413 100644
--- a/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp
+++ b/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp
@@ -39,6 +39,7 @@ private:
private slots:
void textDocumentWriter();
void customDocument();
+ void replaceDocument();
void sourceAndSave_data();
void sourceAndSave();
void loadErrorNoSuchFile();
@@ -197,6 +198,45 @@ void tst_qquicktextdocument::customDocument()
QCOMPARE(fragmentCount, 2);
}
+/*! \internal
+ Verify that it's OK to replace the default QTextDocument that TextEdit creates
+ with a user-created QTextDocument that has different text in it, and that
+ interactive editing continues to function afterwards, independently of
+ the previous document.
+*/
+void tst_qquicktextdocument::replaceDocument() // QTBUG-126267
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("initialText.qml")));
+ QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(window.rootObject());
+ QVERIFY(textEdit);
+ auto *textEditPriv = QQuickTextEditPrivate::get(textEdit);
+ QVERIFY(textEditPriv->ownsDocument);
+ QQuickTextDocument *quickDocument = textEdit->property("textDocument").value<QQuickTextDocument*>();
+ QVERIFY(quickDocument);
+ QPointer<QTextDocument> defaultDocument(quickDocument->textDocument());
+
+ QTextDocument replacementDoc;
+ const QString replacementText("Hello World");
+ {
+ QTextCursor cursor(&replacementDoc);
+ cursor.insertText(replacementText);
+ }
+ QCOMPARE(textEdit->text(), "Hello Qt");
+ QSignalSpy renderSpy(&window, &QQuickWindow::afterRendering);
+ quickDocument->setTextDocument(&replacementDoc);
+ QVERIFY(defaultDocument.isNull()); // deleted because of being replaced (don't leak)
+ QCOMPARE(textEditPriv->ownsDocument, false);
+ QCOMPARE(textEdit->text(), replacementText);
+ QCOMPARE(replacementDoc.toPlainText(), replacementText);
+ QTRY_COMPARE_GT(renderSpy.size(), 0);
+
+ QCOMPARE(window.activeFocusItem(), textEdit);
+ QTest::keyEvent(QTest::KeyAction::Click, &window, Qt::Key_End);
+ QTest::keyEvent(QTest::KeyAction::Click, &window, '!');
+ QCOMPARE(textEdit->text(), replacementText + '!');
+}
+
void tst_qquicktextdocument::sourceAndSave_data()
{
QTest::addColumn<QQuickTextEdit::TextFormat>("textFormat");
diff --git a/tests/auto/quick/qquicktextedit/data/hAlignVisual.qml b/tests/auto/quick/qquicktextedit/data/hAlignVisual.qml
index 1280a655f0..f532a9aa36 100644
--- a/tests/auto/quick/qquicktextedit/data/hAlignVisual.qml
+++ b/tests/auto/quick/qquicktextedit/data/hAlignVisual.qml
@@ -4,11 +4,11 @@ Rectangle {
width: 200
height: 100
- Text {
- objectName: "textItem"
+ TextEdit {
+ objectName: "textEditItem"
text: "AA\nBBBBBBB\nCCCCCCCCCCCCCCCC"
anchors.centerIn: parent
- horizontalAlignment: Text.AlignLeft
+ horizontalAlignment: TextEdit.AlignLeft
font.pointSize: 12
font.family: "Times New Roman"
}
diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
index cc994fe783..c8377aa2d3 100644
--- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
+++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
@@ -245,7 +245,6 @@ private:
void simulateKey(QWindow *, int key, Qt::KeyboardModifiers modifiers = {});
bool isMainFontFixed();
- static bool hasWindowActivation();
QStringList standard;
QStringList richText;
@@ -986,8 +985,8 @@ void tst_qquicktextedit::hAlignVisual()
view.showNormal();
QVERIFY(QTest::qWaitForWindowExposed(&view));
- QQuickText *text = view.rootObject()->findChild<QQuickText*>("textItem");
- QVERIFY(text != nullptr);
+ QQuickTextEdit *text = view.rootObject()->findChild<QQuickTextEdit*>("textEditItem");
+ QVERIFY(text);
// Try to check whether alignment works by checking the number of black
// pixels in the thirds of the grabbed image.
@@ -1014,7 +1013,7 @@ void tst_qquicktextedit::hAlignVisual()
}
{
// HCenter Align
- text->setHAlign(QQuickText::AlignHCenter);
+ text->setHAlign(QQuickTextEdit::AlignHCenter);
QImage image = view.grabWindow();
const int left = numberOfNonWhitePixels(centeredSection1, centeredSection2, image);
const int mid = numberOfNonWhitePixels(centeredSection2, centeredSection3, image);
@@ -1024,7 +1023,7 @@ void tst_qquicktextedit::hAlignVisual()
}
{
// Right Align
- text->setHAlign(QQuickText::AlignRight);
+ text->setHAlign(QQuickTextEdit::AlignRight);
QImage image = view.grabWindow();
const int left = numberOfNonWhitePixels(centeredSection1, centeredSection2, image);
const int mid = numberOfNonWhitePixels(centeredSection2, centeredSection3, image);
@@ -1036,36 +1035,36 @@ void tst_qquicktextedit::hAlignVisual()
text->setWidth(200);
{
- // Left Align
+ // Right Align
QImage image = view.grabWindow();
- int x = qCeil(text->implicitWidth() * view.devicePixelRatio());
- int left = numberOfNonWhitePixels(0, x, image);
- int right = numberOfNonWhitePixels(x, image.width() - x, image);
- QVERIFY2(left > 0, msgNotGreaterThan(left, 0).constData());
- QCOMPARE(right, 0);
+ const int x = image.width() - qCeil(text->implicitWidth() * view.devicePixelRatio());
+ const int left = numberOfNonWhitePixels(0, x, image);
+ const int right = numberOfNonWhitePixels(x, image.width() - x, image);
+ QCOMPARE(left, 0);
+ QVERIFY2(right > 0, msgNotGreaterThan(left, 0).constData());
}
{
// HCenter Align
- text->setHAlign(QQuickText::AlignHCenter);
+ text->setHAlign(QQuickTextEdit::AlignHCenter);
QImage image = view.grabWindow();
- int x1 = qFloor(image.width() - text->implicitWidth() * view.devicePixelRatio()) / 2;
- int x2 = image.width() - x1;
- int left = numberOfNonWhitePixels(0, x1, image);
- int mid = numberOfNonWhitePixels(x1, x2 - x1, image);
- int right = numberOfNonWhitePixels(x2, image.width() - x2, image);
+ const int x1 = qFloor(image.width() - text->implicitWidth() * view.devicePixelRatio()) / 2;
+ const int x2 = image.width() - x1;
+ const int left = numberOfNonWhitePixels(0, x1, image);
+ const int mid = numberOfNonWhitePixels(x1, x2 - x1, image);
+ const int right = numberOfNonWhitePixels(x2, image.width(), image);
QCOMPARE(left, 0);
QVERIFY2(mid > 0, msgNotGreaterThan(left, 0).constData());
QCOMPARE(right, 0);
}
{
- // Right Align
- text->setHAlign(QQuickText::AlignRight);
+ // Left Align
+ text->setHAlign(QQuickTextEdit::AlignLeft);
QImage image = view.grabWindow();
- int x = image.width() - qCeil(text->implicitWidth() * view.devicePixelRatio());
- int left = numberOfNonWhitePixels(0, x, image);
- int right = numberOfNonWhitePixels(x, image.width() - x, image);
- QCOMPARE(left, 0);
- QVERIFY2(right > 0, msgNotGreaterThan(left, 0).constData());
+ const int x = qCeil(text->implicitWidth() * view.devicePixelRatio());
+ const int left = numberOfNonWhitePixels(0, x, image);
+ const int right = numberOfNonWhitePixels(x, image.width() - x, image);
+ QVERIFY2(left > 0, msgNotGreaterThan(left, 0).constData());
+ QCOMPARE(right, 0);
}
}
@@ -3332,11 +3331,6 @@ bool tst_qquicktextedit::isMainFontFixed()
return ret;
}
-bool tst_qquicktextedit::hasWindowActivation()
-{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
-}
-
void tst_qquicktextedit::textInput()
{
QQuickView window;
@@ -6521,8 +6515,8 @@ void tst_qquicktextedit::touchscreenDoesNotSelect()
void tst_qquicktextedit::touchscreenSetsFocusAndMovesCursor()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
+
QQuickView window;
QVERIFY(QQuickTest::showView(window, testFileUrl("twoInAColumn.qml")));
window.requestActivate();
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index b7e689e147..8f8442544f 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -6,6 +6,7 @@
#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtQuickTestUtils/private/testhttpserver_p.h>
#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <private/qinputmethod_p.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
@@ -213,7 +214,6 @@ private:
#if QT_CONFIG(shortcut)
void simulateKeys(QWindow *window, const QKeySequence &sequence);
#endif
- static bool hasWindowActivation();
QQmlEngine engine;
QStringList standard;
@@ -239,11 +239,6 @@ void tst_qquicktextinput::simulateKeys(QWindow *window, const QList<Key> &keys)
}
}
-bool tst_qquicktextinput::hasWindowActivation()
-{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
-}
-
#if QT_CONFIG(shortcut)
void tst_qquicktextinput::simulateKeys(QWindow *window, const QKeySequence &sequence)
@@ -7201,8 +7196,8 @@ void tst_qquicktextinput::touchscreenDoesNotSelect()
void tst_qquicktextinput::touchscreenSetsFocusAndMovesCursor()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
+
QQuickView window;
QVERIFY(QQuickTest::showView(window, testFileUrl("twoInAColumn.qml")));
window.requestActivate();
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index ff3edb3b64..a80827a663 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -3334,7 +3334,7 @@ protected:
}
private:
- static void appendEvent(QQuickItem *filter, QQuickItem *receiver, QEvent *event) {
+ static void appendEvent(QQuickItem *filter, QQuickItem *receiver, QEvent *) {
auto record = DeliveryRecord(filter ? filter->objectName() : QString(), receiver ? receiver->objectName() : QString());
int i = m_deliveryList.size();
if (m_expectedDeliveryList.size() > i && m_expectedDeliveryList[i] == record)
@@ -3384,7 +3384,11 @@ void tst_qquickwindow::testChildMouseEventFilter_data()
QTest::addColumn<InputState>("inputState");
QTest::addColumn<DeliveryRecordVector>("expectedDeliveryOrder");
- for (const QString &eventMode : {"mouse", "touch", "touchToMouse"}) {
+ for (const QString &eventMode : {
+ QStringLiteral("mouse"),
+ QStringLiteral("touch"),
+ QStringLiteral("touchToMouse")
+ }) {
#define desc(txt) qPrintable(QString("%1 events, ").arg(eventMode) + txt)
@@ -4167,7 +4171,7 @@ void tst_qquickwindow::visibilityDoesntClobberWindowState()
window->installEventFilter(&eventFilter);
window->setProperty("visibility", QWindow::FullScreen);
QTRY_VERIFY(eventFilter.events.contains(QEvent::WindowStateChange));
- QCOMPARE(window->windowState(), Qt::WindowFullScreen);
+ QTRY_COMPARE(window->windowState(), Qt::WindowFullScreen);
eventFilter.events.clear();
window->setWindowState(Qt::WindowMaximized);
diff --git a/tests/auto/quick/qquickwindowcontainer/tst_qquickwindowcontainer.cpp b/tests/auto/quick/qquickwindowcontainer/tst_qquickwindowcontainer.cpp
index c702cf96dc..ce3cb0a802 100644
--- a/tests/auto/quick/qquickwindowcontainer/tst_qquickwindowcontainer.cpp
+++ b/tests/auto/quick/qquickwindowcontainer/tst_qquickwindowcontainer.cpp
@@ -16,6 +16,8 @@
#include <QtQuick/qquickwindow.h>
#include <QtQuick/private/qquickwindowcontainer_p.h>
+#define TEST_WINDOW_PARENT 0
+
class tst_QQuickWindowContainer : public QQmlDataTest
{
Q_OBJECT
@@ -34,8 +36,10 @@ private slots:
void windowDestroyed();
void windowLifetimeFollowsContainer();
+#if TEST_WINDOW_PARENT
void deferredVisibilityWithoutWindow();
void windowComponent();
+#endif
private:
std::unique_ptr<QQmlApplicationEngine> m_engine;
@@ -66,8 +70,10 @@ void tst_QQuickWindowContainer::basicFunctionality_data()
{
QTest::addColumn<QPoint>("position");
+#if TEST_WINDOW_PARENT
QTest::newRow("window") << QPoint(100, 100);
QTest::newRow("item") << QPoint(200, 200);
+#endif
QTest::newRow("container") << QPoint(100, 100);
}
@@ -129,6 +135,7 @@ void tst_QQuickWindowContainer::windowLifetimeFollowsContainer()
QVERIFY(windowGuard);
}
+#if TEST_WINDOW_PARENT
void tst_QQuickWindowContainer::deferredVisibilityWithoutWindow()
{
auto *topLevelWindow = qobject_cast<QQuickWindow*>(m_engine->rootObjects().first());
@@ -186,6 +193,7 @@ void tst_QQuickWindowContainer::windowComponent()
QCOMPARE(qobject_cast<QQuickWindow *>(window_item_parent)->parent(), root);
QCOMPARE(qobject_cast<QQuickWindow *>(window_window_parent)->parent(), windowParent);
}
+#endif // TEST_WINDOW_PARENT
QTEST_MAIN(tst_QQuickWindowContainer)
diff --git a/tests/auto/quickcontrols/accessibility/data/actionAccessibility/button.qml b/tests/auto/quickcontrols/accessibility/data/actionAccessibility/button.qml
new file mode 100644
index 0000000000..7e392e9cc3
--- /dev/null
+++ b/tests/auto/quickcontrols/accessibility/data/actionAccessibility/button.qml
@@ -0,0 +1,12 @@
+import QtQuick
+import QtQuick.Controls
+
+Button {
+ action: Action {
+ id: anAction
+ text: "Peaches"
+ Accessible.name: "Peach"
+ Accessible.description: "Show peaches some love"
+ }
+ text: Accessible.description
+}
diff --git a/tests/auto/quickcontrols/accessibility/tst_accessibility.cpp b/tests/auto/quickcontrols/accessibility/tst_accessibility.cpp
index 9774bf4e07..8bdd9453c8 100644
--- a/tests/auto/quickcontrols/accessibility/tst_accessibility.cpp
+++ b/tests/auto/quickcontrols/accessibility/tst_accessibility.cpp
@@ -31,6 +31,8 @@ private slots:
void override();
void ordering();
+
+ void actionAccessibility();
private:
QQmlEngine engine;
};
@@ -274,6 +276,26 @@ void tst_accessibility::ordering()
#endif
}
+void tst_accessibility::actionAccessibility()
+{
+#if QT_CONFIG(accessibility)
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("actionAccessibility/button.qml"));
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
+
+ QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
+ QVERIFY(item);
+ const QString description = "Show peaches some love";
+ QCOMPARE(item->property("text"), description);
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(item);
+ QVERIFY(iface);
+ QCOMPARE(iface->text(QAccessible::Name), "Peach");
+ QCOMPARE(iface->text(QAccessible::Description), description);
+#endif
+}
+
QTEST_MAIN(tst_accessibility)
#include "tst_accessibility.moc"
diff --git a/tests/auto/quickcontrols/controls/CMakeLists.txt b/tests/auto/quickcontrols/controls/CMakeLists.txt
index 6984315b5a..593d87fb75 100644
--- a/tests/auto/quickcontrols/controls/CMakeLists.txt
+++ b/tests/auto/quickcontrols/controls/CMakeLists.txt
@@ -8,6 +8,7 @@ add_subdirectory(fusion)
add_subdirectory(imagine)
add_subdirectory(material)
add_subdirectory(universal)
+add_subdirectory(fluentwinui3)
if(MACOS)
add_subdirectory(macos)
add_subdirectory(ios)
diff --git a/tests/auto/quickcontrols/controls/basic/BLACKLIST b/tests/auto/quickcontrols/controls/basic/BLACKLIST
index b643dd1d9c..b822193f4c 100644
--- a/tests/auto/quickcontrols/controls/basic/BLACKLIST
+++ b/tests/auto/quickcontrols/controls/basic/BLACKLIST
@@ -11,3 +11,8 @@ qnx
[ComboBox::test_keyClose]
macos arm ci # QTBUG-102817
+
+# QTBUG-126236
+[Action::test_repeater]
+macos
+linux
diff --git a/tests/auto/quickcontrols/controls/basic/tst_basic.cpp b/tests/auto/quickcontrols/controls/basic/tst_basic.cpp
index 33417cca55..7e73bd2231 100644
--- a/tests/auto/quickcontrols/controls/basic/tst_basic.cpp
+++ b/tests/auto/quickcontrols/controls/basic/tst_basic.cpp
@@ -8,6 +8,9 @@ int main(int argc, char *argv[])
{
QTEST_SET_MAIN_SOURCE_PATH
qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+ // The tests were originally written before native menus existed,
+ // and some of them try to open menus, which we can't test natively.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
QQuickStyle::setStyle("Basic");
return quick_test_main(argc, argv, "tst_controls::Basic", TST_CONTROLS_DATA);
}
diff --git a/tests/auto/quickcontrols/controls/data/combobox/shader.frag b/tests/auto/quickcontrols/controls/data/combobox/shader.frag
new file mode 100644
index 0000000000..fbbef218e6
--- /dev/null
+++ b/tests/auto/quickcontrols/controls/data/combobox/shader.frag
@@ -0,0 +1,19 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+layout(binding = 1) uniform sampler2D source; // this item
+
+layout(std140, binding = 0) uniform buf {
+ float qt_Opacity; // inherited opacity of this item
+};
+
+
+void main() {
+ vec4 p = texture(source, qt_TexCoord0);
+ lowp float g = dot(p.xyz, vec3(0.344, 0.5, 0.156));
+ fragColor = vec4(g, g, g, p.a) * qt_Opacity;
+}
diff --git a/tests/auto/quickcontrols/controls/data/combobox/shader.frag.qsb b/tests/auto/quickcontrols/controls/data/combobox/shader.frag.qsb
new file mode 100644
index 0000000000..b86ce9a76e
--- /dev/null
+++ b/tests/auto/quickcontrols/controls/data/combobox/shader.frag.qsb
Binary files differ
diff --git a/tests/auto/quickcontrols/controls/data/tst_abstractbutton.qml b/tests/auto/quickcontrols/controls/data/tst_abstractbutton.qml
index 822c703a42..0cf9b8048c 100644
--- a/tests/auto/quickcontrols/controls/data/tst_abstractbutton.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_abstractbutton.qml
@@ -42,6 +42,45 @@ TestCase {
SignalSpy { }
}
+ property var expectedPressSignals: [
+ ["activeFocusChanged", { "activeFocus": true }],
+ ["pressedChanged", { "pressed": true }],
+ ["downChanged", { "down": true }],
+ "pressed"
+ ]
+
+ property var expectedReleaseSignals: [
+ ["pressedChanged", { "pressed": false }],
+ ["downChanged", { "down": false }],
+ "released",
+ "clicked"
+ ]
+
+ property var expectedClickSignals
+
+ property var expectedCheckableClickSignals: [
+ ["activeFocusChanged", { "activeFocus": true }],
+ ["pressedChanged", { "pressed": true }],
+ ["downChanged", { "down": true }],
+ "pressed",
+ ["pressedChanged", { "pressed": false }],
+ ["downChanged", { "down": false }],
+ ["checkedChanged", { "checked": true }],
+ "toggled",
+ "released",
+ "clicked"
+ ]
+
+ function initTestCase() {
+ // AbstractButton has TabFocus on macOS, not StrongFocus.
+ if (Qt.platform.os === "osx") {
+ expectedPressSignals.splice(0, 1)
+ expectedCheckableClickSignals.splice(0, 1)
+ }
+
+ expectedClickSignals = [...expectedPressSignals, ...expectedReleaseSignals]
+ }
+
function init() {
failOnWarning(/.?/)
}
@@ -858,7 +897,7 @@ TestCase {
// Ensure that clicked is emitted when no handler is defined for the pressAndHold() signal.
// Note that even though signal spies aren't considered in QObject::isSignalConnected(),
// we can't use one here to check for pressAndHold(), because otherwise clicked() won't be emitted.
- wait(Qt.styleHints.mousePressAndHoldInterval + 100)
+ wait(Application.styleHints.mousePressAndHoldInterval + 100)
mouseRelease(control)
compare(clickedSpy.count, 1)
}
@@ -1004,4 +1043,137 @@ TestCase {
compare(releasedSpy.count, 0)
compare(clickedSpy.count, 0)
}
+
+ Component {
+ id: signalSequenceSpy
+ SignalSequenceSpy {
+ // List all signals, even ones we might not be interested in for a particular test,
+ // so that it can catch unwanted ones and fail the test.
+ signals: ["pressed", "released", "canceled", "clicked", "toggled", "doubleClicked",
+ "pressedChanged", "downChanged", "checkedChanged", "activeFocusChanged"]
+ }
+ }
+
+ function test_click() {
+ let control = createTemporaryObject(button, testCase)
+ verify(control)
+
+ let sequenceSpy = signalSequenceSpy.createObject(control, { target: control })
+ sequenceSpy.expectedSequence = testCase.expectedClickSignals
+ control.click()
+ verify(sequenceSpy.success)
+ }
+
+ function test_clickCheckableButton() {
+ let control = createTemporaryObject(button, testCase, { checkable: true })
+ verify(control)
+
+ let sequenceSpy = signalSequenceSpy.createObject(control, { target: control })
+ sequenceSpy.expectedSequence = testCase.expectedCheckableClickSignals
+ control.click()
+ verify(sequenceSpy.success)
+ }
+
+ function test_animateClick() {
+ let control = createTemporaryObject(button, testCase)
+ verify(control)
+
+ let sequenceSpy = signalSequenceSpy.createObject(control, { target: control })
+ sequenceSpy.expectedSequence = testCase.expectedClickSignals
+ control.animateClick()
+ tryVerify(() => { return sequenceSpy.success }, 1000)
+ }
+
+ function test_animateClickCheckableButton() {
+ let control = createTemporaryObject(button, testCase, { checkable: true })
+ verify(control)
+
+ let sequenceSpy = signalSequenceSpy.createObject(control, { target: control })
+ sequenceSpy.expectedSequence = testCase.expectedCheckableClickSignals
+ control.animateClick()
+ tryVerify(() => { return sequenceSpy.success }, 1000)
+ }
+
+ function test_animateClickTwice() {
+ let control = createTemporaryObject(button, testCase)
+ verify(control)
+
+ let sequenceSpy = signalSequenceSpy.createObject(control, { target: control })
+ sequenceSpy.expectedSequence = testCase.expectedPressSignals
+ // Check that calling it again before it finishes works as expected.
+ control.animateClick()
+ verify(sequenceSpy.success)
+ // Let the timer progress a bit.
+ wait(0)
+ sequenceSpy.expectedSequence = testCase.expectedReleaseSignals
+ control.animateClick()
+ tryVerify(() => { return sequenceSpy.success }, 1000)
+ }
+
+ function test_clickOnDisabledButton() {
+ let control = createTemporaryObject(button, testCase, { enabled: false })
+ verify(control)
+
+ let sequenceSpy = signalSequenceSpy.createObject(control, { target: control })
+ sequenceSpy.expectedSequence = []
+ control.click()
+ verify(sequenceSpy.success)
+ }
+
+ function test_animateClickOnDisabledButton() {
+ let control = createTemporaryObject(button, testCase, { enabled: false })
+ verify(control)
+
+ let sequenceSpy = signalSequenceSpy.createObject(control, { target: control })
+ sequenceSpy.expectedSequence = []
+ control.animateClick()
+ verify(sequenceSpy.success)
+ }
+
+ Component {
+ id: destroyOnPressButtonComponent
+
+ AbstractButton {
+ width: 100
+ height: 50
+
+ onPressed: destroy(this)
+ }
+ }
+
+ function test_clickDestroyOnPress() {
+ let control = createTemporaryObject(destroyOnPressButtonComponent, testCase)
+ verify(control)
+
+ // Parent it to the testCase, otherwise it will be destroyed when the control is.
+ let destructionSpy = createTemporaryObject(signalSpy, testCase,
+ { target: control.Component, signalName: "destruction" })
+ verify(destructionSpy.valid)
+
+ let sequenceSpy = signalSequenceSpy.createObject(control, { target: control })
+ sequenceSpy.expectedSequence = testCase.expectedClickSignals
+ // Shouldn't crash, etc. Note that destroy() isn't synchronous, and so
+ // the destruction will happen after the release.
+ control.click()
+ verify(sequenceSpy.success)
+ tryCompare(destructionSpy, "count", 1)
+ }
+
+ function test_animateClickDestroyOnPress() {
+ let control = createTemporaryObject(destroyOnPressButtonComponent, testCase)
+ verify(control)
+
+ // Parent it to the testCase, otherwise it will be destroyed when the control is.
+ let destructionSpy = createTemporaryObject(signalSpy, testCase,
+ { target: control.Component, signalName: "destruction" })
+ verify(destructionSpy.valid)
+
+ let sequenceSpy = signalSequenceSpy.createObject(control, { target: control })
+ sequenceSpy.expectedSequence = testCase.expectedPressSignals
+ // Shouldn't crash, etc. Note that destroy() isn't synchronous, but it is processed
+ // on the next frame, so should always come before the release's 100 ms delay.
+ control.animateClick()
+ verify(sequenceSpy.success)
+ tryCompare(destructionSpy, "count", 1)
+ }
}
diff --git a/tests/auto/quickcontrols/controls/data/tst_button.qml b/tests/auto/quickcontrols/controls/data/tst_button.qml
index 0368a229a9..eaf38610cc 100644
--- a/tests/auto/quickcontrols/controls/data/tst_button.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_button.qml
@@ -4,6 +4,7 @@
import QtQuick
import QtTest
import QtQuick.Controls
+import Qt.test.controls
TestCase {
id: testCase
@@ -448,12 +449,20 @@ TestCase {
verify(!textLabel)
compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
+ if (StyleInfo.styleName === "Material") {
+ compare(control.leftPadding, Material.buttonLeftPadding(false, true))
+ compare(control.rightPadding, Material.buttonRightPadding(false, true, false))
+ }
break;
case Button.TextOnly:
verify(!iconImage)
verify(textLabel)
compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ if (StyleInfo.styleName === "Material") {
+ compare(control.leftPadding, Material.buttonLeftPadding(false, false))
+ compare(control.rightPadding, Material.buttonRightPadding(false, false, true))
+ }
break;
case Button.TextUnderIcon:
verify(iconImage)
@@ -461,6 +470,10 @@ TestCase {
compare(iconImage.x, (control.availableWidth - iconImage.width) / 2)
compare(textLabel.x, (control.availableWidth - textLabel.width) / 2)
verify(iconImage.y < textLabel.y)
+ if (StyleInfo.styleName === "Material") {
+ compare(control.leftPadding, Material.buttonLeftPadding(false, true))
+ compare(control.rightPadding, Material.buttonRightPadding(false, true, true))
+ }
break;
case Button.TextBesideIcon:
verify(iconImage)
@@ -471,6 +484,10 @@ TestCase {
verify(iconImage.x < textLabel.x)
compare(iconImage.y, (control.availableHeight - iconImage.height) / 2)
compare(textLabel.y, (control.availableHeight - textLabel.height) / 2)
+ if (StyleInfo.styleName === "Material") {
+ compare(control.leftPadding, Material.buttonLeftPadding(false, true))
+ compare(control.rightPadding, Material.buttonRightPadding(false, true, true))
+ }
break;
}
}
diff --git a/tests/auto/quickcontrols/controls/data/tst_checkbox.qml b/tests/auto/quickcontrols/controls/data/tst_checkbox.qml
index 6c3b859e40..93677e8a20 100644
--- a/tests/auto/quickcontrols/controls/data/tst_checkbox.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_checkbox.qml
@@ -201,7 +201,7 @@ TestCase {
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true, "checkState": Qt.Checked }],
"pressed"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
@@ -220,7 +220,7 @@ TestCase {
// release outside
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false, "checkState": Qt.Unchecked }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
diff --git a/tests/auto/quickcontrols/controls/data/tst_combobox.qml b/tests/auto/quickcontrols/controls/data/tst_combobox.qml
index 9f852e29e4..9e933b59b7 100644
--- a/tests/auto/quickcontrols/controls/data/tst_combobox.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_combobox.qml
@@ -5,6 +5,7 @@ import QtQuick
import QtQuick.Window
import QtTest
import QtQuick.Controls
+import Qt.test.controls
import QtQuick.NativeStyle as NativeStyle
TestCase {
@@ -74,16 +75,7 @@ TestCase {
objectName: "ShaderFX"
width: rect.width
height: rect.height
- fragmentShader: "
- uniform lowp sampler2D source; // this item
- uniform lowp float qt_Opacity; // inherited opacity of this item
- varying highp vec2 qt_TexCoord0;
- void main() {
- lowp vec4 p = texture2D(source, qt_TexCoord0);
- lowp float g = dot(p.xyz, vec3(0.344, 0.5, 0.156));
- gl_FragColor = vec4(g, g, g, p.a) * qt_Opacity;
- }"
-
+ fragmentShader: "combobox/shader.frag.qsb"
}
}
}
@@ -878,22 +870,27 @@ TestCase {
// Account for when a transition of a scale from 0.9-1.0 that it is placed above right away and not below
// first just because there is room at the 0.9 scale
if (control.popup.enter !== null) {
- // hide
- mouseClick(control)
- compare(control.pressed, false)
- tryCompare(control.popup, "visible", false)
- control.y = control.Window.height - (control.popup.contentItem.height * 0.99)
- var popupYSpy = createTemporaryObject(signalSpy, testCase, {target: control.popup, signalName: "yChanged"})
- verify(popupYSpy.valid)
- mousePress(control)
- compare(control.pressed, true)
- compare(control.popup.visible, false)
- mouseRelease(control)
- compare(control.pressed, false)
- compare(control.popup.visible, true)
- tryCompare(control.popup.enter, "running", false)
- verify(control.popup.contentItem.y < control.y)
- verify(popupYSpy.count === 1)
+ // test only if there is a scale animation
+ let scaleAnimation = control.popup.enter.animations.some((animation) => {
+ return (animation instanceof PropertyAnimation && animation.property === "scale")
+ });
+ if (scaleAnimation) {
+ // hide
+ mouseClick(control)
+ compare(control.pressed, false)
+ tryCompare(control.popup, "visible", false)
+ control.y = control.Window.height - (control.popup.contentItem.height * 0.99)
+ var popupYSpy = createTemporaryObject(signalSpy, testCase, {target: control.popup, signalName: "yChanged"})
+ verify(popupYSpy.valid)
+ mousePress(control)
+ compare(control.pressed, true)
+ compare(control.popup.visible, false)
+ mouseRelease(control)
+ compare(control.pressed, false)
+ tryCompare(control.popup, "opened", true)
+ verify(control.popup.contentItem.y < control.y)
+ verify(popupYSpy.count === 1)
+ }
}
var leftLayoutMargin = control.background.layoutMargins === undefined ? 0 : control.popup.layoutMargins.left
@@ -949,7 +946,8 @@ TestCase {
// Check on the second opening that it has the same y position as before
if (i !== 0) {
// y should not have changed again
- verify(popupYSpy.count === 0)
+ if (StyleInfo.styleName !== "FluentWinUI3") // the popup y in FluentWinUI3 depends on the implicitHeight
+ verify(popupYSpy.count === 0)
verify(y === control.innerCombo.popup.y)
} else {
// In some cases on the initial show, y changes more than once
@@ -1024,6 +1022,7 @@ TestCase {
compare(activatedSpy.count, 0)
compare(highlightedSpy.count, 0)
compare(control.popup.visible, true)
+ tryCompare(control.popup, "opened", true)
// press - move - release inside - activated - closed
touch.press(0, content).commit()
@@ -1787,7 +1786,7 @@ TestCase {
// Ensure that it's open so that the popup's implicitHeight changes when we increase the model count.
control.popup.open()
- tryCompare(control.popup, "visible", true)
+ tryCompare(control.popup, "opened", true)
// Add lots of items to the model. The popup should take up the entire height of the window.
control.model = 100
@@ -1799,6 +1798,8 @@ TestCase {
control.model = 0
control.popup.open()
tryCompare(control.popup, "visible", true)
+ if (control.popup.enter !== null)
+ tryCompare(control.popup.enter, "running", false)
compare(control.popup.height, control.popup.topPadding + control.popup.bottomPadding)
}
@@ -1956,7 +1957,7 @@ TestCase {
// and then that ComboBox loses focus, its currentIndex should change
// to the index of the edit text (assuming a match is found).
function test_currentIndexChangeOnLostFocus() {
- if (Qt.styleHints.tabFocusBehavior !== Qt.TabFocusAllControls)
+ if (Application.styleHints.tabFocusBehavior !== Qt.TabFocusAllControls)
skip("This platform only allows tab focus for text controls")
let theModel = []
@@ -2004,11 +2005,16 @@ TestCase {
compare(currentIndexSpy.count, 1)
}
+ readonly property font testFont: ({
+ family: "Arial",
+ pixelSize: 12
+ })
+
Component {
- id: appFontTextFieldComponent
+ id: fixedFontTextFieldComponent
TextField {
objectName: "appFontTextField"
- font: Qt.application.font
+ font: testCase.testFont
// We don't want the background's implicit width to interfere with our tests,
// which are about implicit width of the contentItem of ComboBox, which is by default TextField.
background: null
@@ -2016,14 +2022,14 @@ TestCase {
}
Component {
- id: appFontContentItemComboBoxComponent
+ id: fixedFontContentItemComboBoxComponent
ComboBox {
// Override the contentItem so that the font doesn't vary between styles.
contentItem: TextField {
objectName: "appFontContentItemTextField"
// We do this just to be extra sure that the font never comes from the control,
- // as we want it to match that of the TextField in the appFontTextFieldComponent.
- font: Qt.application.font
+ // as we want it to match that of the TextField in the fixedFontTextFieldComponent.
+ font: testCase.testFont
background: null
}
}
@@ -2077,14 +2083,14 @@ TestCase {
function test_implicitContentWidthPolicy_ContentItemImplicitWidth() {
// Set ContentItemImplicitWidth and ensure that implicitContentWidth is as wide as the current item
// by comparing it against the implicitWidth of an identical TextField
- let control = createTemporaryObject(appFontContentItemComboBoxComponent, testCase, {
+ let control = createTemporaryObject(fixedFontContentItemComboBoxComponent, testCase, {
model: ["Short", "Kinda long"],
implicitContentWidthPolicy: ComboBox.ContentItemImplicitWidth
})
verify(control)
compare(control.implicitContentWidthPolicy, ComboBox.ContentItemImplicitWidth)
- let textField = createTemporaryObject(appFontTextFieldComponent, testCase)
+ let textField = createTemporaryObject(fixedFontTextFieldComponent, testCase)
verify(textField)
// Don't set any text on textField because we're not accounting for the widest
// text here, so we want to compare it against an empty TextField.
@@ -2103,14 +2109,14 @@ TestCase {
}
function test_implicitContentWidthPolicy_WidestText(data) {
- let control = createTemporaryObject(appFontContentItemComboBoxComponent, testCase, {
+ let control = createTemporaryObject(fixedFontContentItemComboBoxComponent, testCase, {
model: data.model,
implicitContentWidthPolicy: ComboBox.WidestText
})
verify(control)
compare(control.implicitContentWidthPolicy, ComboBox.WidestText)
- let textField = createTemporaryObject(appFontTextFieldComponent, testCase)
+ let textField = createTemporaryObject(fixedFontTextFieldComponent, testCase)
verify(textField)
textField.text = "Kinda long"
// Note that we don't need to change the current index here, as the implicitContentWidth
@@ -2137,7 +2143,7 @@ TestCase {
// Changes in font should result in the implicitContentWidth being updated.
textField.font.pixelSize *= 2
// We have to change the contentItem's font size manually since we break the
- // style's binding to the control's font when we set Qt.application.font to it.
+ // style's binding to the control's font when we set the fixed font on it.
control.contentItem.font.pixelSize *= 2
control.font.pixelSize *= 2
compare(Math.ceil(control.implicitContentWidth), Math.ceil(textField.implicitWidth))
@@ -2148,14 +2154,14 @@ TestCase {
}
function test_implicitContentWidthPolicy_WidestTextWhenCompleted(data) {
- let control = createTemporaryObject(appFontContentItemComboBoxComponent, testCase, {
+ let control = createTemporaryObject(fixedFontContentItemComboBoxComponent, testCase, {
model: data.model,
implicitContentWidthPolicy: ComboBox.WidestTextWhenCompleted
})
verify(control)
compare(control.implicitContentWidthPolicy, ComboBox.WidestTextWhenCompleted)
- let textField = createTemporaryObject(appFontTextFieldComponent, testCase)
+ let textField = createTemporaryObject(fixedFontTextFieldComponent, testCase)
verify(textField)
textField.text = "Kinda long"
compare(Math.ceil(control.implicitContentWidth), Math.ceil(textField.implicitWidth))
diff --git a/tests/auto/quickcontrols/controls/data/tst_control.qml b/tests/auto/quickcontrols/controls/data/tst_control.qml
index a3e65f2b0f..581f76d0c6 100644
--- a/tests/auto/quickcontrols/controls/data/tst_control.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_control.qml
@@ -1064,7 +1064,7 @@ TestCase {
verify(control)
compare(control.hovered, false)
- compare(control.hoverEnabled, Qt.styleHints.useHoverEffects)
+ compare(control.hoverEnabled, Application.styleHints.useHoverEffects)
control.hoverEnabled = false
@@ -1098,7 +1098,7 @@ TestCase {
function test_hoverEnabled() {
let control = createTemporaryObject(component, testCase)
- compare(control.hoverEnabled, Qt.styleHints.useHoverEffects)
+ compare(control.hoverEnabled, Application.styleHints.useHoverEffects)
let child = component.createObject(control)
let grandChild = component.createObject(child)
diff --git a/tests/auto/quickcontrols/controls/data/tst_delaybutton.qml b/tests/auto/quickcontrols/controls/data/tst_delaybutton.qml
index 708e6a8a22..62f04d175e 100644
--- a/tests/auto/quickcontrols/controls/data/tst_delaybutton.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_delaybutton.qml
@@ -172,7 +172,7 @@ TestCase {
"pressed",
"activated"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
tryVerify(function() { return sequenceSpy.success})
@@ -190,7 +190,7 @@ TestCase {
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }],
["downChanged", { "down": true }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
@@ -208,7 +208,7 @@ TestCase {
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }],
["downChanged", { "down": true }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
diff --git a/tests/auto/quickcontrols/controls/data/tst_radiobutton.qml b/tests/auto/quickcontrols/controls/data/tst_radiobutton.qml
index a4d0a08d7d..3415c9518c 100644
--- a/tests/auto/quickcontrols/controls/data/tst_radiobutton.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_radiobutton.qml
@@ -156,7 +156,7 @@ TestCase {
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
@@ -171,7 +171,7 @@ TestCase {
// release outside
sequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(sequenceSpy.success)
diff --git a/tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml b/tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml
index 879e8c68d4..79a51bd4c3 100644
--- a/tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_selectionrectangle.qml
@@ -73,6 +73,22 @@ TestCase {
}
Component {
+ id: delegateWithTapHandlerComp
+ Rectangle {
+ implicitWidth: 100
+ implicitHeight: 50
+ color: selected ? "lightblue" : "transparent"
+ border.width: 1
+ required property bool selected
+
+ TapHandler {
+ // This tap handler will block the tap handler in
+ // QQuickTableView from being called.
+ }
+ }
+ }
+
+ Component {
id: tableviewComp
TableView {
id: tableView
@@ -574,6 +590,43 @@ TestCase {
verify(!bottomRightHandle.visible)
}
+ function test_delegateWithTapHandler() {
+ // Check that we clear the current selection if you start a new
+ // mouse drag selection on top of a delegate with a tap handler.
+ let tableView = createTemporaryObject(tableviewComp, testCase)
+ verify(tableView)
+
+ tableView.delegate = delegateWithTapHandlerComp;
+ let selectionRectangle = tableView.selectionRectangle
+ verify(selectionRectangle)
+
+ selectionRectangle.selectionMode = SelectionRectangle.Drag
+ tableView.selectionMode = TableView.ExtendedSelection
+
+ verify(waitForItemPolished(tableView))
+
+ let item0_0 = tableView.itemAtIndex(tableView.index(0, 0))
+ let item1_1 = tableView.itemAtIndex(tableView.index(1, 1))
+ verify(item0_0)
+ verify(item1_1)
+
+ tableView.selectionModel.select(tableView.index(0, 0), ItemSelectionModel.Select)
+ compare(tableView.selectionModel.selectedIndexes.length, 1)
+ compare(tableView.selectionModel.selectedIndexes[0], tableView.index(0, 0))
+
+ // A drag should clear the current selection and select a new cell
+ mouseDrag(tableView.contentItem, item1_1.x, item1_1.y, 10, 10, Qt.LeftButton)
+ compare(tableView.selectionModel.selectedIndexes.length, 1)
+ compare(tableView.selectionModel.selectedIndexes[0], tableView.index(1, 1))
+
+ // Verify that a PressAndHold works as well
+ selectionRectangle.selectionMode = SelectionRectangle.PressAndHold
+ mousePress(tableView, item0_0.x, item0_0.y, Qt.LeftButton)
+ mouseRelease(tableView, item0_0.x, item0_0.y, Qt.LeftButton, Qt.NoModifier, 2000)
+ compare(tableView.selectionModel.selectedIndexes.length, 1)
+ compare(tableView.selectionModel.selectedIndexes[0], tableView.index(0, 0))
+ }
+
// TODO: enable this test when mouseDrag sends modifiers for all mouse events
// (including mouseMove)
// function test_multi_selection() {
diff --git a/tests/auto/quickcontrols/controls/data/tst_stackview.qml b/tests/auto/quickcontrols/controls/data/tst_stackview.qml
index 3d304f385a..7e373c66ff 100644
--- a/tests/auto/quickcontrols/controls/data/tst_stackview.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_stackview.qml
@@ -534,7 +534,7 @@ TestCase {
// Escape special Regexp characters with a '\' (backslash) prefix so that \a str can be
// used as a Regexp pattern.
- function escapeRegExp(str: string) {
+ function escapeRegExp(str: string): string {
// "$&" is the last matched substring
return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}
diff --git a/tests/auto/quickcontrols/controls/data/tst_swipedelegate.qml b/tests/auto/quickcontrols/controls/data/tst_swipedelegate.qml
index 4e4022a1c5..ed63f7d39e 100644
--- a/tests/auto/quickcontrols/controls/data/tst_swipedelegate.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_swipedelegate.qml
@@ -14,7 +14,7 @@ TestCase {
when: windowShown
name: "SwipeDelegate"
- readonly property int dragDistance: Math.max(20, Qt.styleHints.startDragDistance + 5)
+ readonly property int dragDistance: Math.max(20, Application.styleHints.startDragDistance + 5)
Component {
id: backgroundFillComponent
@@ -657,6 +657,20 @@ TestCase {
width: 100
height: 120
+ property int rotation: 0
+
+ transform: [
+ Rotation {
+ angle: rotation
+ origin.x: 0
+ origin.y: 0
+ },
+ Translate {
+ x: (rotation === 90) ? parent.width : 0
+ y: 0
+ }
+ ]
+
model: ListModel {
ListElement { name: "Apple" }
ListElement { name: "Orange" }
@@ -714,15 +728,20 @@ TestCase {
function test_removableDelegates_data() {
return [
{ tag: "mouse", touch: false },
- { tag: "touch", touch: true }
+ { tag: "touch", touch: true },
+ { tag: "mouse_rotation_90", touch: false, rotation: 90 },
+ { tag: "touch_rotation_90", touch: true, rotation: 90 },
]
}
- function test_removableDelegates() {
+ function test_removableDelegates(data) {
let listView = createTemporaryObject(removableDelegatesComponent, testCase);
verify(listView);
compare(listView.count, 3);
+ if (data.rotation)
+ listView.rotation = data.rotation;
+
let touch = data.touch ? touchEvent(listView) : null
// Expose the remove button.
diff --git a/tests/auto/quickcontrols/controls/data/tst_swipeview.qml b/tests/auto/quickcontrols/controls/data/tst_swipeview.qml
index 8d59c4a09a..3a7558c0e4 100644
--- a/tests/auto/quickcontrols/controls/data/tst_swipeview.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_swipeview.qml
@@ -563,7 +563,7 @@ TestCase {
}
function test_focus() {
- if (Qt.styleHints.tabFocusBehavior !== Qt.TabFocusAllControls)
+ if (Application.styleHints.tabFocusBehavior !== Qt.TabFocusAllControls)
skip("This platform only allows tab focus for text controls")
let control = createTemporaryObject(focusSwipeViewComponent, testCase)
diff --git a/tests/auto/quickcontrols/controls/data/tst_switch.qml b/tests/auto/quickcontrols/controls/data/tst_switch.qml
index 40fdbaff0d..c193a10d21 100644
--- a/tests/auto/quickcontrols/controls/data/tst_switch.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_switch.qml
@@ -212,7 +212,7 @@ TestCase {
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -229,7 +229,7 @@ TestCase {
// release on the right
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -248,7 +248,7 @@ TestCase {
// release on the left
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -267,7 +267,7 @@ TestCase {
// release in the middle
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, 0, 0).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -428,7 +428,7 @@ TestCase {
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, 0).commit()
compare(control.position, 1.0)
compare(control.checked, true)
@@ -464,7 +464,7 @@ TestCase {
// press-drag-release from and to outside the indicator
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width - 1).commit()
compare(control.position, 0.0)
compare(control.checked, false)
diff --git a/tests/auto/quickcontrols/controls/data/tst_switchdelegate.qml b/tests/auto/quickcontrols/controls/data/tst_switchdelegate.qml
index c03555f59c..7468b8ac69 100644
--- a/tests/auto/quickcontrols/controls/data/tst_switchdelegate.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_switchdelegate.qml
@@ -203,7 +203,7 @@ TestCase {
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -220,7 +220,7 @@ TestCase {
// release on the right
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -239,7 +239,7 @@ TestCase {
// release on the left
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width / 2, control.height / 2).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -258,7 +258,7 @@ TestCase {
// release in the middle
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, 0, 0).commit()
compare(control.pressed, true)
verify(spy.success)
@@ -419,7 +419,7 @@ TestCase {
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }],
"pressed"]
// Don't want to double-click.
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, 0).commit()
compare(control.position, 1.0)
compare(control.checked, true)
@@ -455,7 +455,7 @@ TestCase {
// press-drag-release from and to outside the indicator
spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }],
"pressed"]
- wait(Qt.styleHints.mouseDoubleClickInterval + 50)
+ wait(Application.styleHints.mouseDoubleClickInterval + 50)
touch.press(0, control, control.width - 1).commit()
compare(control.position, 0.0)
compare(control.checked, false)
diff --git a/tests/auto/quickcontrols/controls/data/tst_tabbar.qml b/tests/auto/quickcontrols/controls/data/tst_tabbar.qml
index f4b8d170ce..19ba2a9678 100644
--- a/tests/auto/quickcontrols/controls/data/tst_tabbar.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_tabbar.qml
@@ -20,7 +20,12 @@ TestCase {
Component {
id: tabBar
- TabBar { }
+ TabBar {
+ topPadding: 0
+ bottomPadding: 0
+ leftPadding: 0
+ rightPadding: 0
+ }
}
Component {
@@ -533,7 +538,8 @@ TestCase {
compare(control.implicitWidth, control.contentWidth + control.leftPadding + control.rightPadding)
compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding)
- let expectedWidth = tab3.contentItem.implicitWidth + tab3.leftPadding + tab3.rightPadding
+ let expectedWidth = Math.max(tab3.implicitBackgroundWidth + tab3.leftInset + tab3.rightInset,
+ tab3.implicitContentWidth + tab3.leftPadding + tab3.rightPadding)
tab3.width = tab3.implicitWidth
tab3.height = tab3.implicitHeight
tryCompare(tab1, "width", (control.width - 2 * data.spacing - expectedWidth) / 2)
diff --git a/tests/auto/quickcontrols/controls/data/tst_tumbler.qml b/tests/auto/quickcontrols/controls/data/tst_tumbler.qml
index c5c567b7d2..3033dc756a 100644
--- a/tests/auto/quickcontrols/controls/data/tst_tumbler.qml
+++ b/tests/auto/quickcontrols/controls/data/tst_tumbler.qml
@@ -60,8 +60,8 @@ TestCase {
// visualItemIndex is from 0 to the amount of visible items.
function itemCenterPos(visualItemIndex) {
- var halfDelegateHeight = tumblerDelegateHeight / 2;
- var yCenter = tumbler.y + tumbler.topPadding + halfDelegateHeight
+ let halfDelegateHeight = tumblerDelegateHeight / 2;
+ let yCenter = tumbler.y + tumbler.topPadding + halfDelegateHeight
+ (tumblerDelegateHeight * visualItemIndex);
return Qt.point(tumblerXCenter(), yCenter);
}
@@ -71,22 +71,22 @@ TestCase {
}
function checkItemSizes() {
- var contentChildren = tumbler.wrap ? tumblerView.children : tumblerView.contentItem.children;
+ let contentChildren = tumbler.wrap ? tumblerView.children : tumblerView.contentItem.children;
verify(contentChildren.length >= tumbler.count);
- for (var i = 0; i < contentChildren.length; ++i) {
+ for (let i = 0; i < contentChildren.length; ++i) {
compare(contentChildren[i].width, tumbler.availableWidth);
compare(contentChildren[i].height, tumblerDelegateHeight);
}
}
function findView(parent) {
- for (var i = 0; i < parent.children.length; ++i) {
- var child = parent.children[i];
+ for (let i = 0; i < parent.children.length; ++i) {
+ let child = parent.children[i];
if (child.hasOwnProperty("currentIndex")) {
return child;
}
- var grandChild = findView(child);
+ let grandChild = findView(child);
if (grandChild)
return grandChild;
}
@@ -95,13 +95,13 @@ TestCase {
}
function findDelegateWithText(parent, text) {
- for (var i = 0; i < parent.children.length; ++i) {
- var child = parent.children[i];
+ for (let i = 0; i < parent.children.length; ++i) {
+ let child = parent.children[i];
if (child.hasOwnProperty("text") && child.text === text) {
return child;
}
- var grandChild = findDelegateWithText(child, text);
+ let grandChild = findDelegateWithText(child, text);
if (grandChild)
return grandChild;
}
@@ -113,9 +113,11 @@ TestCase {
text: modelData
}
- function test_defaults() {
+ function init() {
failOnWarning(/.?/)
+ }
+ function test_defaults() {
let control = createTemporaryObject(defaultTumbler, testCase)
verify(control)
}
@@ -144,7 +146,7 @@ TestCase {
waitForRendering(tumbler);
// Set it through user interaction.
- var pos = Qt.point(tumblerXCenter(), tumbler.height / 2);
+ let pos = Qt.point(tumblerXCenter(), tumbler.height / 2);
mouseDrag(tumbler, pos.x, pos.y, 0, tumbler.height / 3, Qt.LeftButton, Qt.NoModifier, 200);
tryCompare(tumblerView, "offset", 1);
compare(tumbler.currentIndex, 4);
@@ -283,7 +285,7 @@ TestCase {
tumblerView.highlightMoveDuration = 0;
// Navigate upwards through entire wheel.
- for (var j = 0; j < tumbler.count - 1; ++j) {
+ for (let j = 0; j < tumbler.count - 1; ++j) {
keyClick(Qt.Key_Up, Qt.NoModifier);
tryCompare(tumblerView, "offset", j + 1);
compare(tumbler.currentIndex, tumbler.count - 1 - j);
@@ -294,7 +296,7 @@ TestCase {
compare(tumbler.currentIndex, 0);
// Navigate downwards through entire wheel.
- for (j = 0; j < tumbler.count - 1; ++j) {
+ for (let j = 0; j < tumbler.count - 1; ++j) {
keyClick(Qt.Key_Down, Qt.NoModifier);
tryCompare(tumblerView, "offset", tumbler.count - 1 - j);
compare(tumbler.currentIndex, j + 1);
@@ -314,9 +316,9 @@ TestCase {
checkItemSizes();
wait(tumblerView.highlightMoveDuration);
- var firstItemCenterPos = itemCenterPos(1);
- var firstItem = tumblerView.itemAt(firstItemCenterPos.x, firstItemCenterPos.y);
- var actualPos = testCase.mapFromItem(firstItem, 0, 0);
+ let firstItemCenterPos = itemCenterPos(1);
+ let firstItem = tumblerView.itemAt(firstItemCenterPos.x, firstItemCenterPos.y);
+ let actualPos = testCase.mapFromItem(firstItem, 0, 0);
compare(actualPos.x, tumbler.leftPadding);
compare(actualPos.y, tumbler.topPadding + 40);
@@ -332,13 +334,13 @@ TestCase {
fuzzyCompare(actualPos.x, tumbler.leftPadding, 0.0001);
fuzzyCompare(actualPos.y, tumbler.topPadding, 0.0001);
- var secondItemCenterPos = itemCenterPos(1);
- var secondItem = tumblerView.itemAt(secondItemCenterPos.x, secondItemCenterPos.y);
+ let secondItemCenterPos = itemCenterPos(1);
+ let secondItem = tumblerView.itemAt(secondItemCenterPos.x, secondItemCenterPos.y);
verify(secondItem);
verify(firstItem.y < secondItem.y);
- var thirdItemCenterPos = itemCenterPos(2);
- var thirdItem = tumblerView.itemAt(thirdItemCenterPos.x, thirdItemCenterPos.y);
+ let thirdItemCenterPos = itemCenterPos(2);
+ let thirdItem = tumblerView.itemAt(thirdItemCenterPos.x, thirdItemCenterPos.y);
verify(thirdItem);
verify(firstItem.y < thirdItem.y);
verify(secondItem.y < thirdItem.y);
@@ -348,7 +350,7 @@ TestCase {
tumbler = createTemporaryObject(tumblerComponent, testCase);
verify(tumbler);
- var mouseArea = createTemporaryQmlObject(
+ let mouseArea = createTemporaryQmlObject(
"import QtQuick; TextInput { activeFocusOnTab: true; width: 50; height: 50 }", testCase, "");
tumbler.forceActiveFocus();
@@ -360,7 +362,7 @@ TestCase {
}
function test_datePicker() {
- var component = Qt.createComponent("TumblerDatePicker.qml");
+ let component = Qt.createComponent("TumblerDatePicker.qml");
compare(component.status, Component.Ready, component.errorString());
tumbler = createTemporaryObject(component, testCase);
// Should not be any warnings.
@@ -422,7 +424,7 @@ TestCase {
}
function test_listViewTimePicker() {
- var root = createTemporaryObject(timePickerComponent, testCase);
+ let root = createTemporaryObject(timePickerComponent, testCase);
verify(root);
mouseDrag(root.minuteTumbler, root.minuteTumbler.width / 2, root.minuteTumbler.height / 2, 0, 50);
@@ -431,7 +433,7 @@ TestCase {
}
function test_displacement_data() {
- var data = [
+ let data = [
// At 0 offset, the first item is current.
{ count: 6, index: 0, offset: 0, expectedDisplacement: 0 },
{ count: 6, index: 1, offset: 0, expectedDisplacement: -1 },
@@ -462,8 +464,8 @@ TestCase {
// count == 1
{ count: 1, index: 0, offset: 0, expectedDisplacement: 0 }
];
- for (var i = 0; i < data.length; ++i) {
- var row = data[i];
+ for (let i = 0; i < data.length; ++i) {
+ let row = data[i];
row.tag = "count=" + row.count
+ " delegate" + row.index
+ " offset=" + row.offset
@@ -498,7 +500,7 @@ TestCase {
tumbler.model = data.count;
compare(tumbler.count, data.count);
- var delegate = findChild(tumblerView, "delegate" + data.index);
+ let delegate = findChild(tumblerView, "delegate" + data.index);
verify(delegate);
tumblerView.offset = data.offset;
@@ -555,7 +557,7 @@ TestCase {
function test_explicitlyNonwrapping() {
// Check that explicitly setting wrap to false works even when it was implicitly false.
- var explicitlyNonWrapping = createTemporaryObject(twoItemTumbler, testCase);
+ let explicitlyNonWrapping = createTemporaryObject(twoItemTumbler, testCase);
verify(explicitlyNonWrapping);
tryCompare(explicitlyNonWrapping, "wrap", false);
@@ -572,7 +574,7 @@ TestCase {
function test_explicitlyWrapping() {
// Check that explicitly setting wrap to true works even when it was implicitly true.
- var explicitlyWrapping = createTemporaryObject(tenItemTumbler, testCase);
+ let explicitlyWrapping = createTemporaryObject(tenItemTumbler, testCase);
verify(explicitlyWrapping);
compare(explicitlyWrapping.wrap, true);
@@ -644,14 +646,14 @@ TestCase {
}
function test_customContentItemAtConstruction(data) {
- var tumbler = createTemporaryObject(data.component, testCase);
+ let tumbler = createTemporaryObject(data.component, testCase);
// Shouldn't assert.
tumbler.model = 5;
compare(tumbler.count, 5);
tumbler.currentIndex = 2;
- var tumblerView = findView(tumbler);
+ let tumblerView = findView(tumbler);
compare(tumblerView.currentIndex, 2);
tumblerView.incrementCurrentIndex();
@@ -666,10 +668,10 @@ TestCase {
}
function findFirstDelegateWithText(view, text) {
- var delegate = null;
- var contentItem = view.hasOwnProperty("contentItem") ? view.contentItem : view;
- for (var i = 0; i < contentItem.children.length && !delegate; ++i) {
- var child = contentItem.children[i];
+ let delegate = null;
+ let contentItem = view.hasOwnProperty("contentItem") ? view.contentItem : view;
+ for (let i = 0; i < contentItem.children.length && !delegate; ++i) {
+ let child = contentItem.children[i];
if (child.hasOwnProperty("text") && child.text === text)
delegate = child;
}
@@ -692,16 +694,16 @@ TestCase {
tumbler.currentIndex = 2;
compare(tumblerView.currentIndex, 2);
- var contentItemComponent = Qt.createComponent(data.componentPath);
+ let contentItemComponent = Qt.createComponent(data.componentPath);
compare(contentItemComponent.status, Component.Ready);
- var customContentItem = createTemporaryObject(contentItemComponent, tumbler);
+ let customContentItem = createTemporaryObject(contentItemComponent, tumbler);
tumbler.contentItem = customContentItem;
compare(tumbler.count, 5);
tumblerView = findView(tumbler);
compare(tumblerView.currentIndex, 2);
- var delegate = findFirstDelegateWithText(tumblerView, "Custom2");
+ let delegate = findFirstDelegateWithText(tumblerView, "Custom2");
verify(delegate);
compare(delegate.height, defaultImplicitDelegateHeight);
tryCompare(delegate.Tumbler, "displacement", 0);
@@ -712,9 +714,9 @@ TestCase {
}
function test_displacementListView_data() {
- var offset = defaultListViewTumblerOffset;
+ let offset = defaultListViewTumblerOffset;
- var data = [
+ let data = [
// At 0 contentY, the first item is current.
{ contentY: offset, expectedDisplacements: [
{ index: 0, displacement: 0 },
@@ -741,8 +743,8 @@ TestCase {
{ index: 4, displacement: -0.5 } ]
}
];
- for (var i = 0; i < data.length; ++i) {
- var row = data[i];
+ for (let i = 0; i < data.length; ++i) {
+ let row = data[i];
row.tag = "contentY=" + row.contentY;
}
return data;
@@ -758,9 +760,9 @@ TestCase {
// Ensure assumptions about the tumbler used in our data() function are correct.
tumblerView = findView(tumbler);
compare(tumblerView.contentY, -defaultImplicitDelegateHeight);
- var delegateCount = 0;
- var listView = tumblerView;
- var listViewContentItem = tumblerView.contentItem;
+ let delegateCount = 0;
+ let listView = tumblerView;
+ let listViewContentItem = tumblerView.contentItem;
// We use the mouse instead of setting contentY directly, otherwise the
// items snap back into place. This doesn't seem to be an issue for
@@ -779,25 +781,25 @@ TestCase {
// to begin with, nothing changes (the displacement was always very close to 0 in the end).
// Ensure that we at least cover the distance required to reach the desired contentY.
- var distanceToReachContentY = data.contentY - defaultListViewTumblerOffset;
- var distance = Math.abs(distanceToReachContentY) + tumbler.height / 2;
+ let distanceToReachContentY = data.contentY - defaultListViewTumblerOffset;
+ let distance = Math.abs(distanceToReachContentY) + tumbler.height / 2;
// If distanceToReachContentY is 0, we're testing 0 displacement, so we don't need to do anything.
if (distanceToReachContentY != 0) {
mousePress(tumbler, tumblerXCenter(), tumblerYCenter());
- var dragDirection = distanceToReachContentY > 0 ? -1 : 1;
- for (var i = 0; i < distance && Math.floor(listView.contentY) !== Math.floor(data.contentY); ++i) {
+ let dragDirection = distanceToReachContentY > 0 ? -1 : 1;
+ for (let i = 0; i < distance && Math.floor(listView.contentY) !== Math.floor(data.contentY); ++i) {
mouseMove(tumbler, tumblerXCenter(), tumblerYCenter() + i * dragDirection);
wait(1); // because Flickable pays attention to velocity, we need some time between movements (qtdeclarative ebf07c3)
}
}
- for (var i = 0; i < data.expectedDisplacements.length; ++i) {
- var delegate = findChild(listViewContentItem, "delegate" + data.expectedDisplacements[i].index);
+ for (let i = 0; i < data.expectedDisplacements.length; ++i) {
+ let delegate = findChild(listViewContentItem, "delegate" + data.expectedDisplacements[i].index);
verify(delegate);
compare(delegate.height, defaultImplicitDelegateHeight);
// Due to the way we must perform this test, we can't expect high precision.
- var expectedDisplacement = data.expectedDisplacements[i].displacement;
+ let expectedDisplacement = data.expectedDisplacements[i].displacement;
fuzzyCompare(delegate.displacement, expectedDisplacement, 0.1,
"Delegate of ListView-based Tumbler at index " + data.expectedDisplacements[i].index
+ " has displacement of " + delegate.displacement + " when it should be " + expectedDisplacement);
@@ -810,10 +812,10 @@ TestCase {
function test_listViewFlickAboveBounds_data() {
// Tests that flicking above the bounds when already at the top of the
// tumbler doesn't result in an incorrect displacement.
- var data = [];
+ let data = [];
// Less than two items doesn't make sense. The default visibleItemCount
// is 3, so we test a bit more than double that.
- for (var i = 2; i <= 7; ++i) {
+ for (let i = 2; i <= 7; ++i) {
data.push({ tag: i + " items", model: i });
}
return data;
@@ -830,21 +832,21 @@ TestCase {
mousePress(tumbler, tumblerXCenter(), tumblerYCenter());
// Ensure it's stationary.
- var listView = tumblerView;
+ let listView = tumblerView;
compare(listView.contentY, defaultListViewTumblerOffset);
// We could just move up until the contentY changed, but this is safer.
- var distance = tumbler.height;
- var changed = false;
+ let distance = tumbler.height;
+ let changed = false;
- for (var i = 0; i < distance && !changed; ++i) {
+ for (let i = 0; i < distance && !changed; ++i) {
mouseMove(tumbler, tumblerXCenter(), tumblerYCenter() + i, 10);
// Don't test until the contentY has actually changed.
if (Math.abs(listView.contentY) - listView.preferredHighlightBegin > 0.01) {
- for (var delegateIndex = 0; delegateIndex < Math.min(tumbler.count, tumbler.visibleItemCount); ++delegateIndex) {
- var delegate = findChild(listView.contentItem, "delegate" + delegateIndex);
+ for (let delegateIndex = 0; delegateIndex < Math.min(tumbler.count, tumbler.visibleItemCount); ++delegateIndex) {
+ let delegate = findChild(listView.contentItem, "delegate" + delegateIndex);
verify(delegate);
verify(delegate.displacement <= -delegateIndex, "Delegate at index " + delegateIndex + " has a displacement of "
@@ -871,7 +873,7 @@ TestCase {
}
function test_visibleItemCount_data() {
- var data = [
+ let data = [
// e.g. {0: 2} = {delegate index: y pos / delegate height}
// Skip item at index 3, because it's out of view.
{ model: 6, visibleItemCount: 5, expectedYPositions: {0: 2, 1: 3, 2: 4, 4: 0} },
@@ -880,7 +882,7 @@ TestCase {
{ model: 2, visibleItemCount: 1, expectedYPositions: {0: 0} },
];
- for (var i = 0; i < data.length; ++i) {
+ for (let i = 0; i < data.length; ++i) {
data[i].tag = "items=" + data[i].model + ", visibleItemCount=" + data[i].visibleItemCount;
}
return data;
@@ -895,11 +897,11 @@ TestCase {
tumbler.model = data.model;
compare(tumbler.count, data.model);
- for (var delegateIndex = 0; delegateIndex < data.visibleItemCount; ++delegateIndex) {
+ for (let delegateIndex = 0; delegateIndex < data.visibleItemCount; ++delegateIndex) {
if (data.expectedYPositions.hasOwnProperty(delegateIndex)) {
- var delegate = findChild(tumblerView, "delegate" + delegateIndex);
+ let delegate = findChild(tumblerView, "delegate" + delegateIndex);
verify(delegate, "Delegate found at index " + delegateIndex);
- var expectedYPos = data.expectedYPositions[delegateIndex] * tumblerDelegateHeight;
+ let expectedYPos = data.expectedYPositions[delegateIndex] * tumblerDelegateHeight;
compare(delegate.mapToItem(tumbler.contentItem, 0, 0).y, expectedYPos);
}
}
@@ -928,7 +930,7 @@ TestCase {
createTemporaryObject(noParentDelegateComponent, null);
ignoreWarning(/.*Tumbler: attempting to access attached property on item without an \"index\" property/);
- var object = createTemporaryObject(noParentDelegateComponent, testCase);
+ let object = createTemporaryObject(noParentDelegateComponent, testCase);
verify(object);
}
@@ -947,15 +949,15 @@ TestCase {
}
function test_padding_data() {
- var data = [];
+ let data = [];
data.push({ padding: 0 });
data.push({ padding: 10 });
data.push({ left: 10, top: 10 });
data.push({ right: 10, bottom: 10 });
- for (var i = 0; i < data.length; ++i) {
- var tag = "";
+ for (let i = 0; i < data.length; ++i) {
+ let tag = "";
if (data[i].padding !== undefined)
tag += "padding: " + data[i].padding + " ";
@@ -1004,24 +1006,24 @@ TestCase {
compare(tumbler.contentItem.x, tumbler.leftPadding);
compare(tumbler.contentItem.y, tumbler.topPadding);
- var pathView = tumbler.contentItem;
- var expectedDelegateHeight = tumbler.availableHeight / tumbler.visibleItemCount;
- var itemIndicesInVisualOrder = [4, 0, 1];
- for (var i = 0; i < itemIndicesInVisualOrder.length; ++i) {
- var delegate = findChild(pathView, "delegate" + itemIndicesInVisualOrder[i]);
+ let pathView = tumbler.contentItem;
+ let expectedDelegateHeight = tumbler.availableHeight / tumbler.visibleItemCount;
+ let itemIndicesInVisualOrder = [4, 0, 1];
+ for (let i = 0; i < itemIndicesInVisualOrder.length; ++i) {
+ let delegate = findChild(pathView, "delegate" + itemIndicesInVisualOrder[i]);
verify(delegate, "Couldn't find delegate at index " + itemIndicesInVisualOrder[i]
+ " (iteration " + i + " out of " + (pathView.children.length - 1) + ")");
compare(delegate.width, tumbler.availableWidth);
compare(delegate.height, expectedDelegateHeight);
- var expectedY = tumbler.topPadding + i * expectedDelegateHeight;
- var mappedPos = delegate.mapToItem(null, delegate.width / 2, 0);
+ let expectedY = tumbler.topPadding + i * expectedDelegateHeight;
+ let mappedPos = delegate.mapToItem(null, delegate.width / 2, 0);
fuzzyCompare(mappedPos.y, expectedY, 0.5,
"Tumbler's PathView delegate at index " + itemIndicesInVisualOrder[i]
+ " should have a y pos of " + expectedY + ", but it's actually " + mappedPos.y.toFixed(20));
- var expectedX = tumbler.leftPadding;
+ let expectedX = tumbler.leftPadding;
compare(delegate.mapToItem(null, 0, 0).x, expectedX,
"Tumbler's PathView delegate at index " + itemIndicesInVisualOrder[i]
+ " should have a x pos of " + expectedX + ", but it's actually " + mappedPos.x.toFixed(20));
@@ -1050,7 +1052,7 @@ TestCase {
mousePress(tumbler, tumbler.width / 2, tumbler.height / 2, Qt.LeftButton)
compare(tumbler.moving, false)
- for (var y = tumbler.height / 2; y >= tumbler.height / 4; y -= 10)
+ for (let y = tumbler.height / 2; y >= tumbler.height / 4; y -= 10)
mouseMove(tumbler, tumbler.width / 2, y, 1)
compare(tumbler.moving, true)
@@ -1084,15 +1086,15 @@ TestCase {
}
function test_qtbug61374() {
- var row = createTemporaryObject(qtbug61374Component, testCase);
+ let row = createTemporaryObject(qtbug61374Component, testCase);
verify(row);
- var tumbler = row.tumbler;
+ let tumbler = row.tumbler;
tryCompare(tumbler, "currentIndex", 2);
tumblerView = findView(tumbler);
- var label = row.label;
+ let label = row.label;
compare(label.text, "2");
}
@@ -1124,16 +1126,16 @@ TestCase {
tryCompare(tumbler, "moving", false)
compare(tumbler.visibleItemCount, 5)
- for (var i = 0; i < 5; ++i) {
+ for (let i = 0; i < 5; ++i) {
// Find the item through its text, as that's easier than child/itemAt().
- var text = data.expectedVisibleIndices[i].toString()
- var item = findDelegateWithText(tumblerView, text)
+ let text = data.expectedVisibleIndices[i].toString()
+ let item = findDelegateWithText(tumblerView, text)
verify(item, "found no item with text \"" + text + "\"")
compare(item.text, data.expectedVisibleIndices[i].toString())
// Ensure that it's at the position we expect.
- var expectedPos = itemTopLeftPos(i)
- var actualPos = testCase.mapFromItem(item, 0, 0)
+ let expectedPos = itemTopLeftPos(i)
+ let actualPos = testCase.mapFromItem(item, 0, 0)
compare(actualPos.x, expectedPos.x, "expected delegate with text " + item.text
+ " to have an x pos of " + expectedPos.x + " but it was " + actualPos.x)
compare(actualPos.y, expectedPos.y, "expected delegate with text " + item.text
@@ -1150,7 +1152,7 @@ TestCase {
}
function test_setCurrentIndexOnImperativeModelChange() {
- var tumbler = createTemporaryObject(setCurrentIndexOnImperativeModelChangeComponent, testCase);
+ let tumbler = createTemporaryObject(setCurrentIndexOnImperativeModelChangeComponent, testCase);
verify(tumbler);
tumbler.model = 4
@@ -1187,10 +1189,10 @@ TestCase {
}
function test_setCurrentIndexOnDeclarativeModelChange() {
- var root = createTemporaryObject(setCurrentIndexOnDeclarativeModelChangeComponent, testCase);
+ let root = createTemporaryObject(setCurrentIndexOnDeclarativeModelChangeComponent, testCase);
verify(root);
- var tumbler = root.tumbler;
+ let tumbler = root.tumbler;
compare(tumbler.count, 4);
compare(tumbler.wrap, false);
tumblerView = findView(tumbler);
@@ -1217,7 +1219,7 @@ TestCase {
currentIndex: 15
})
- var delegate = findChild(tumblerView, "delegate15")
+ let delegate = findChild(tumblerView, "delegate15")
verify(delegate)
tryCompare(delegate, "displacement", 0)
@@ -1242,7 +1244,7 @@ TestCase {
}
function test_initialCurrentIndex() {
- var tumbler = createTemporaryObject(initialCurrentIndexTumbler, testCase, {wrap: true});
+ let tumbler = createTemporaryObject(initialCurrentIndexTumbler, testCase, {wrap: true});
compare(tumbler.currentIndex, 4);
tumbler = createTemporaryObject(initialCurrentIndexTumbler, testCase, {wrap: false});
compare(tumbler.currentIndex, 4);
@@ -1282,7 +1284,7 @@ TestCase {
touch.press(0, tumblerView, control.width / 2, control.height / 2).commit()
// Move slowly, otherwise its considered as flick which cause current index
// to be varied according to its velocity
- var scrollOffset = control.height / 2
+ let scrollOffset = control.height / 2
for (; scrollOffset > delegateHeight / 2; scrollOffset-=5) {
touch.move(0, tumblerView, control.width / 2, scrollOffset).commit()
}
diff --git a/tests/auto/quickcontrols/controls/fluentwinui3/BLACKLIST b/tests/auto/quickcontrols/controls/fluentwinui3/BLACKLIST
new file mode 100644
index 0000000000..3867b52f90
--- /dev/null
+++ b/tests/auto/quickcontrols/controls/fluentwinui3/BLACKLIST
@@ -0,0 +1,14 @@
+# See qtbase/src/testlib/qtestblacklist.cpp for format
+
+# until adding FluentWinUI3's own BusyIndicator implementation
+[BusyIndicator::test_visibility]
+*
+
+# until adding FluentWinUI3's own Page implementation
+[Page::test_layout]
+*
+
+# QTBUG-95750
+[RangeSlider::test_overlappingHandles]
+b2qt
+qnx
diff --git a/tests/auto/quickcontrols/controls/fluentwinui3/CMakeLists.txt b/tests/auto/quickcontrols/controls/fluentwinui3/CMakeLists.txt
new file mode 100644
index 0000000000..384b8c47f4
--- /dev/null
+++ b/tests/auto/quickcontrols/controls/fluentwinui3/CMakeLists.txt
@@ -0,0 +1,38 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_fluentwinui3 LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/../data/tst_*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_fluentwinui3
+ GUI
+ QMLTEST
+ SOURCES
+ tst_fluentwinui3.cpp
+ DEFINES
+ TST_CONTROLS_DATA="${CMAKE_CURRENT_SOURCE_DIR}/../data"
+ LIBRARIES
+ Qt::Gui
+ Qt::QuickControls2
+ TESTDATA ${test_data}
+)
+
+# Make the QML files available to Creator's locator.
+target_sources(tst_fluentwinui3
+ PRIVATE
+ ${test_data}
+)
+
+set_source_files_properties(${test_data}
+ PROPERTIES
+ HEADER_FILE_ONLY ON
+)
diff --git a/tests/auto/quickcontrols/controls/fluentwinui3/dependencies.qml b/tests/auto/quickcontrols/controls/fluentwinui3/dependencies.qml
new file mode 100644
index 0000000000..2b442ac527
--- /dev/null
+++ b/tests/auto/quickcontrols/controls/fluentwinui3/dependencies.qml
@@ -0,0 +1,6 @@
+import QtTest
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.FluentWinUI3
+
+TestCase { }
diff --git a/tests/auto/quickcontrols/controls/fluentwinui3/dummy_imports.qml b/tests/auto/quickcontrols/controls/fluentwinui3/dummy_imports.qml
new file mode 100644
index 0000000000..66e184f138
--- /dev/null
+++ b/tests/auto/quickcontrols/controls/fluentwinui3/dummy_imports.qml
@@ -0,0 +1,12 @@
+// This file exists for the sole purpose for qmlimportscanner to find
+// which modules it needs to extract for deployment.
+// Otherwise, it fails to find the imports that are expressed in C++.
+
+import QtQml
+import QtCore
+import QtQuick
+import QtQuick.NativeStyle
+import QtQuick.Layouts
+import Qt.labs.qmlmodels
+
+QtObject { }
diff --git a/tests/auto/quickcontrols/controls/fluentwinui3/tst_fluentwinui3.cpp b/tests/auto/quickcontrols/controls/fluentwinui3/tst_fluentwinui3.cpp
new file mode 100644
index 0000000000..9f67b3dc9e
--- /dev/null
+++ b/tests/auto/quickcontrols/controls/fluentwinui3/tst_fluentwinui3.cpp
@@ -0,0 +1,13 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtQuickTest/quicktest.h>
+#include <QtQuickControls2/qquickstyle.h>
+
+int main(int argc, char *argv[])
+{
+ QTEST_SET_MAIN_SOURCE_PATH
+ qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+ QQuickStyle::setStyle("FluentWinUI3");
+ return quick_test_main(argc, argv, "tst_controls::FluentWinUI3", TST_CONTROLS_DATA);
+}
diff --git a/tests/auto/quickcontrols/controls/fusion/tst_fusion.cpp b/tests/auto/quickcontrols/controls/fusion/tst_fusion.cpp
index 4485ca0c70..3c1f255d6e 100644
--- a/tests/auto/quickcontrols/controls/fusion/tst_fusion.cpp
+++ b/tests/auto/quickcontrols/controls/fusion/tst_fusion.cpp
@@ -8,6 +8,9 @@ int main(int argc, char *argv[])
{
QTEST_SET_MAIN_SOURCE_PATH
qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+ // The tests were originally written before native menus existed,
+ // and some of them try to open menus, which we can't test natively.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
QQuickStyle::setStyle("Fusion");
return quick_test_main(argc, argv, "tst_controls::Fusion", TST_CONTROLS_DATA);
}
diff --git a/tests/auto/quickcontrols/controls/imagine/tst_imagine.cpp b/tests/auto/quickcontrols/controls/imagine/tst_imagine.cpp
index 54c363797b..ca9ff3fddd 100644
--- a/tests/auto/quickcontrols/controls/imagine/tst_imagine.cpp
+++ b/tests/auto/quickcontrols/controls/imagine/tst_imagine.cpp
@@ -8,6 +8,9 @@ int main(int argc, char *argv[])
{
QTEST_SET_MAIN_SOURCE_PATH
qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+ // The tests were originally written before native menus existed,
+ // and some of them try to open menus, which we can't test natively.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
QQuickStyle::setStyle("Imagine");
return quick_test_main(argc, argv, "tst_controls::Imagine", TST_CONTROLS_DATA);
}
diff --git a/tests/auto/quickcontrols/controls/ios/tst_ios.cpp b/tests/auto/quickcontrols/controls/ios/tst_ios.cpp
index 11c6f35b0b..b34a580e3c 100644
--- a/tests/auto/quickcontrols/controls/ios/tst_ios.cpp
+++ b/tests/auto/quickcontrols/controls/ios/tst_ios.cpp
@@ -8,6 +8,9 @@ int main(int argc, char *argv[])
{
QTEST_SET_MAIN_SOURCE_PATH
qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+ // The tests were originally written before native menus existed,
+ // and some of them try to open menus, which we can't test natively.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
QQuickStyle::setStyle("iOS");
return quick_test_main(argc, argv, "tst_controls::iOS", TST_CONTROLS_DATA);
}
diff --git a/tests/auto/quickcontrols/controls/macos/tst_macos.cpp b/tests/auto/quickcontrols/controls/macos/tst_macos.cpp
index 1ba0ebf587..91ce22cc0b 100644
--- a/tests/auto/quickcontrols/controls/macos/tst_macos.cpp
+++ b/tests/auto/quickcontrols/controls/macos/tst_macos.cpp
@@ -10,6 +10,9 @@ int main(int argc, char *argv[])
qputenv("QML_NO_TOUCH_COMPRESSION", "1");
// See comment in tst_windows.cpp.
qputenv("QT_QUICK_CONTROLS_IGNORE_CUSTOMIZATION_WARNINGS", "1");
+ // The tests were originally written before native menus existed,
+ // and some of them try to open menus, which we can't test natively.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
QQuickStyle::setStyle("macOS");
return quick_test_main(argc, argv, "tst_controls::macOS", TST_CONTROLS_DATA);
}
diff --git a/tests/auto/quickcontrols/controls/material/tst_material.cpp b/tests/auto/quickcontrols/controls/material/tst_material.cpp
index 782397a592..9a76046d23 100644
--- a/tests/auto/quickcontrols/controls/material/tst_material.cpp
+++ b/tests/auto/quickcontrols/controls/material/tst_material.cpp
@@ -8,6 +8,9 @@ int main(int argc, char *argv[])
{
QTEST_SET_MAIN_SOURCE_PATH
qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+ // The tests were originally written before native menus existed,
+ // and some of them try to open menus, which we can't test natively.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
QQuickStyle::setStyle("Material");
return quick_test_main(argc, argv, "tst_controls::Material", TST_CONTROLS_DATA);
}
diff --git a/tests/auto/quickcontrols/controls/universal/tst_universal.cpp b/tests/auto/quickcontrols/controls/universal/tst_universal.cpp
index 2d9e687bea..3cd41be836 100644
--- a/tests/auto/quickcontrols/controls/universal/tst_universal.cpp
+++ b/tests/auto/quickcontrols/controls/universal/tst_universal.cpp
@@ -8,6 +8,9 @@ int main(int argc, char *argv[])
{
QTEST_SET_MAIN_SOURCE_PATH
qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+ // The tests were originally written before native menus existed,
+ // and some of them try to open menus, which we can't test natively.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
QQuickStyle::setStyle("Universal");
return quick_test_main(argc, argv, "tst_controls::Universal", TST_CONTROLS_DATA);
}
diff --git a/tests/auto/quickcontrols/controls/windows/tst_windows.cpp b/tests/auto/quickcontrols/controls/windows/tst_windows.cpp
index 221ff116dd..bcd8fa35d8 100644
--- a/tests/auto/quickcontrols/controls/windows/tst_windows.cpp
+++ b/tests/auto/quickcontrols/controls/windows/tst_windows.cpp
@@ -17,6 +17,9 @@ int main(int argc, char *argv[])
// issued when default-constructing controls. For that we have
// tst_customization::noCustomizationWarningsForDefaultControls.
qputenv("QT_QUICK_CONTROLS_IGNORE_CUSTOMIZATION_WARNINGS", "1");
+ // The tests were originally written before native menus existed,
+ // and some of them try to open menus, which we can't test natively.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
QQuickStyle::setStyle("Windows");
return quick_test_main(argc, argv, "tst_controls::Windows", TST_CONTROLS_DATA);
}
diff --git a/tests/auto/quickcontrols/focus/tst_focus.cpp b/tests/auto/quickcontrols/focus/tst_focus.cpp
index 5d745813dc..9f68e3b61d 100644
--- a/tests/auto/quickcontrols/focus/tst_focus.cpp
+++ b/tests/auto/quickcontrols/focus/tst_focus.cpp
@@ -15,6 +15,7 @@
#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQuickTemplates2/private/qquicktextfield_p.h>
#include <QtQuickControls2/qquickstyle.h>
#include <QtQuickControlsTestUtils/private/controlstestutils_p.h>
@@ -29,6 +30,7 @@ public:
tst_focus();
private slots:
+ void init() override;
void initTestCase() override;
void navigation_data();
@@ -50,8 +52,15 @@ tst_focus::tst_focus()
{
}
+void tst_focus::init()
+{
+ QTest::failOnWarning(QRegularExpression(".?"));
+}
+
void tst_focus::initTestCase()
{
+ SKIP_IF_NO_WINDOW_ACTIVATION
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
QQuickStyle::setStyle("Basic");
QQmlDataTest::initTestCase();
}
@@ -236,7 +245,7 @@ void tst_focus::reason()
QQuickControl *customText = view.findChild<QQuickControl *>("customText");
QQuickControl *customItem = view.findChild<QQuickControl *>("customItem");
// not a QQuickControl subclass
- QQuickItem *textfield = view.findChild<QQuickItem *>("textfield");
+ QQuickTextField *textfield = view.findChild<QQuickTextField *>("textfield");
// helper for clicking into a control
const auto itemCenter = [](const QQuickItem *item) -> QPoint {
@@ -265,21 +274,35 @@ void tst_focus::reason()
}
QCOMPARE(control->focusReason(), Qt::ActiveWindowFocusReason);
+ QSignalSpy controlSpy(control, SIGNAL(focusReasonChanged()));
+ QSignalSpy textfieldSpy(textfield, SIGNAL(focusReasonChanged()));
+ QSignalSpy customItemSpy(customItem, SIGNAL(focusReasonChanged()));
+ int controlSpyCount = 0, textfieldSpyCount = 0, customItemSpyCount = 0;
+ QVERIFY(!controlSpy.count());
+ QVERIFY(!textfieldSpy.count());
+ QVERIFY(!customItemSpy.count());
+
// test setter/getter
control->setFocus(false, Qt::MouseFocusReason);
QCOMPARE(control->focusReason(), Qt::MouseFocusReason);
+ QCOMPARE(controlSpy.count(), ++controlSpyCount);
control->setFocus(true, Qt::TabFocusReason);
QCOMPARE(control->focusReason(), Qt::TabFocusReason);
+ QCOMPARE(controlSpy.count(), ++controlSpyCount);
control->setFocus(false, Qt::BacktabFocusReason);
QCOMPARE(control->focusReason(), Qt::BacktabFocusReason);
+ QCOMPARE(controlSpy.count(), ++controlSpyCount);
control->forceActiveFocus(Qt::ShortcutFocusReason);
QCOMPARE(control->focusReason(), Qt::ShortcutFocusReason);
+ QCOMPARE(controlSpy.count(), ++controlSpyCount);
control->setFocusReason(Qt::PopupFocusReason);
QCOMPARE(control->focusReason(), Qt::PopupFocusReason);
+ QCOMPARE(controlSpy.count(), ++controlSpyCount);
// programmatic focus changes
combobox->setFocus(true, Qt::OtherFocusReason);
QCOMPARE(control->focusReason(), Qt::OtherFocusReason);
+ QCOMPARE(controlSpy.count(), ++controlSpyCount);
QVERIFY(combobox->hasFocus());
QVERIFY(combobox->hasActiveFocus());
@@ -316,27 +339,35 @@ void tst_focus::reason()
QVERIFY(customItem->hasActiveFocus());
QCOMPARE(customText->focusReason(), Qt::TabFocusReason);
QCOMPARE(customItem->focusReason(), Qt::TabFocusReason);
+ QCOMPARE(customItemSpy.count(),++customItemSpyCount);
customItem->setFocusReason(Qt::NoFocusReason);
+ QCOMPARE(customItemSpy.count(),++customItemSpyCount);
QTest::keyClick(&view, Qt::Key_Tab);
QVERIFY(textfield->hasFocus());
QVERIFY(textfield->hasActiveFocus());
QCOMPARE(qApp->focusObject(), textfield);
QCOMPARE(customItem->focusReason(), Qt::TabFocusReason);
+ QCOMPARE(customItemSpy.count(),++customItemSpyCount);
+ QCOMPARE(textfieldSpy.count(), ++textfieldSpyCount);
QTest::keyClick(&view, Qt::Key_Tab);
QVERIFY(control->hasFocus());
QVERIFY(control->hasActiveFocus());
QCOMPARE(control->focusReason(), Qt::TabFocusReason);
+ QCOMPARE(controlSpy.count(), ++controlSpyCount);
// backtab -> BacktabFocusReason
QTest::keyClick(&view, Qt::Key_Tab, Qt::ShiftModifier);
QVERIFY(textfield->hasFocus());
QCOMPARE(control->focusReason(), Qt::BacktabFocusReason);
+ QCOMPARE(controlSpy.count(), ++controlSpyCount);
+ QCOMPARE(textfieldSpy.count(), ++textfieldSpyCount);
QTest::keyClick(&view, Qt::Key_Tab, Qt::ShiftModifier);
QVERIFY(customItem->hasFocus());
QCOMPARE(customItem->focusReason(), Qt::BacktabFocusReason);
+ QCOMPARE(customItemSpy.count(),++customItemSpyCount);
QTest::keyClick(&view, Qt::Key_Tab, Qt::ShiftModifier);
QVERIFY(customText->hasFocus());
@@ -391,11 +422,15 @@ void tst_focus::reason()
QVERIFY(customItem->hasActiveFocus());
QCOMPARE(customText->focusReason(), Qt::MouseFocusReason);
QCOMPARE(customItem->focusReason(), Qt::MouseFocusReason);
+ QCOMPARE(customItemSpy.count(),++customItemSpyCount);
customItem->setFocusReason(Qt::NoFocusReason);
+ QCOMPARE(customItemSpy.count(),++customItemSpyCount);
QTest::mouseClick(&view, Qt::LeftButton, {}, itemCenter(textfield));
QCOMPARE(customItem->focusReason(), Qt::MouseFocusReason);
+ QCOMPARE(customItemSpy.count(),++customItemSpyCount);
customItem->setFocusReason(Qt::NoFocusReason);
+ QCOMPARE(customItemSpy.count(),++customItemSpyCount);
customText->setFocusReason(Qt::NoFocusReason);
#if QT_CONFIG(wheelevent)
@@ -406,11 +441,13 @@ void tst_focus::reason()
QGuiApplication::sendEvent(customItem, &wheelEvent);
QVERIFY(customItem->hasActiveFocus());
QCOMPARE(customItem->focusReason(), Qt::MouseFocusReason);
+ QCOMPARE(customItemSpy.count(),++customItemSpyCount);
// Popup opens -> PopupFocusReason
QTest::mouseClick(&view, Qt::RightButton, {}, itemCenter(control));
QTRY_VERIFY(!customItem->hasActiveFocus());
QCOMPARE(customItem->focusReason(), Qt::PopupFocusReason);
+ QCOMPARE(customItemSpy.count(),++customItemSpyCount);
QTest::keyClick(&view, Qt::Key_Escape); // close the popup
#endif
}
diff --git a/tests/auto/quickcontrols/font/tst_font.cpp b/tests/auto/quickcontrols/font/tst_font.cpp
index bdb73bbf4b..ec8e927693 100644
--- a/tests/auto/quickcontrols/font/tst_font.cpp
+++ b/tests/auto/quickcontrols/font/tst_font.cpp
@@ -113,7 +113,7 @@ void tst_font::font()
QFETCH(QString, testFile);
QFETCH(QFont, expectedFont);
- if (QSysInfo::productType().compare(QLatin1String("osx"), Qt::CaseInsensitive) == 0
+ if (QSysInfo::productType().compare(QLatin1String("macos"), Qt::CaseInsensitive) == 0
&& qgetenv("QTEST_ENVIRONMENT").split(' ').contains("CI")) {
QSKIP("This test crashes on macOS: QTBUG-70063");
}
diff --git a/tests/auto/quickcontrols/palette/data/comboBoxPopupWithThemeDefault.qml b/tests/auto/quickcontrols/palette/data/comboBoxPopupWithThemeDefault.qml
new file mode 100644
index 0000000000..592793fa3f
--- /dev/null
+++ b/tests/auto/quickcontrols/palette/data/comboBoxPopupWithThemeDefault.qml
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 400
+ height: 400
+
+ property alias comboBox: comboBox
+
+ ComboBox {
+ id: comboBox
+ model: 1
+ }
+}
diff --git a/tests/auto/quickcontrols/palette/data/toolTipPaletteUpdate.qml b/tests/auto/quickcontrols/palette/data/toolTipPaletteUpdate.qml
new file mode 100644
index 0000000000..3968c54cd0
--- /dev/null
+++ b/tests/auto/quickcontrols/palette/data/toolTipPaletteUpdate.qml
@@ -0,0 +1,19 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: window
+
+ palette { toolTipBase: "white"; toolTipText: "black"}
+
+ Button {
+ objectName: "button"
+ text: qsTr("Button with Tooltip")
+
+ ToolTip.visible: false
+ ToolTip.text: qsTr("This is a tool tip.")
+ }
+}
diff --git a/tests/auto/quickcontrols/palette/tst_palette.cpp b/tests/auto/quickcontrols/palette/tst_palette.cpp
index 75ee023bb7..11a30e5a4b 100644
--- a/tests/auto/quickcontrols/palette/tst_palette.cpp
+++ b/tests/auto/quickcontrols/palette/tst_palette.cpp
@@ -18,6 +18,7 @@
#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
#include <QtQuickTemplates2/private/qquicktheme_p_p.h>
#include <QtQuickTemplates2/private/qquickbutton_p.h>
+#include <QtQuickTemplates2/private/qquicktooltip_p.h>
#include <QtQuickControls2/qquickstyle.h>
#include <QSignalSpy>
@@ -58,6 +59,10 @@ private slots:
void comboBoxPopup_data();
void comboBoxPopup();
+ void comboBoxPopupWithThemeDefault_data();
+ void comboBoxPopupWithThemeDefault();
+
+ void toolTipPaletteUpdate();
};
tst_palette::tst_palette()
@@ -612,6 +617,65 @@ void tst_palette::comboBoxPopup()
QColorConstants::Red);
}
+void tst_palette::comboBoxPopupWithThemeDefault_data()
+{
+ QTest::addColumn<QString>("style");
+ QTest::addColumn<QColor>("expectedComboBoxPopupBackgroundColor");
+
+ QTest::newRow("Basic") << "Basic" << QColor::fromRgb(0xFFFFFF);
+
+ // We can't test Fusion because it uses the default application palette,
+ // which is the default-constructed QPalette, so the test would always pass.
+}
+
+void tst_palette::comboBoxPopupWithThemeDefault()
+{
+ QFETCH(QString, style);
+ QFETCH(QColor, expectedComboBoxPopupBackgroundColor);
+
+ qmlClearTypeRegistrations();
+ QQuickStyle::setStyle(style);
+
+ QQuickApplicationHelper helper(this, "comboBoxPopupWithThemeDefault.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ const auto *comboBox = window->property("comboBox").value<QQuickComboBox *>();
+ QVERIFY(comboBox);
+ const auto *comboBoxBackground = comboBox->popup()->background();
+ QCOMPARE(comboBoxBackground->property("color"), expectedComboBoxPopupBackgroundColor);
+}
+
+void tst_palette::toolTipPaletteUpdate()
+{
+ QQuickApplicationHelper helper(this, "toolTipPaletteUpdate.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *button = window->findChild<QQuickButton *>("button");
+ QVERIFY(button);
+ auto *attachedToolTip = button->findChild<QQuickToolTipAttached *>();
+ QVERIFY(attachedToolTip);
+ auto *toolTip = attachedToolTip->toolTip();
+ QVERIFY(toolTip);
+
+ auto windowPalette = QQuickWindowPrivate::get(window)->palette();
+ auto toolTipPalette = QQuickPopupPrivate::get(toolTip)->palette();
+
+ QCOMPARE(toolTipPalette->toolTipBase(), windowPalette->toolTipBase());
+ QCOMPARE(toolTipPalette->toolTipText(), windowPalette->toolTipText());
+
+ windowPalette->setToolTipBase(Qt::blue);
+ windowPalette->setToolTipText(Qt::red);
+
+ QCOMPARE(toolTipPalette->toolTipBase(), windowPalette->toolTipBase());
+ QCOMPARE(toolTipPalette->toolTipText(), windowPalette->toolTipText());
+}
+
QTEST_MAIN(tst_palette)
#include "tst_palette.moc"
diff --git a/tests/auto/quickcontrols/qquickapplicationwindow/data/backgroundSize.qml b/tests/auto/quickcontrols/qquickapplicationwindow/data/backgroundSize.qml
index 0e4ed277d0..db5470986f 100644
--- a/tests/auto/quickcontrols/qquickapplicationwindow/data/backgroundSize.qml
+++ b/tests/auto/quickcontrols/qquickapplicationwindow/data/backgroundSize.qml
@@ -9,6 +9,7 @@ ApplicationWindow {
height: 400
background: Item {
+ objectName: "background"
implicitWidth: 123
implicitHeight: 456
}
diff --git a/tests/auto/quickcontrols/qquickapplicationwindow/data/explicitBackgroundSizeBinding.qml b/tests/auto/quickcontrols/qquickapplicationwindow/data/explicitBackgroundSizeBinding.qml
new file mode 100644
index 0000000000..67fdf7808c
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickapplicationwindow/data/explicitBackgroundSizeBinding.qml
@@ -0,0 +1,21 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: window
+ width: 600
+ height: 400
+
+ property real scaleFactor: 1
+
+ background: Rectangle {
+ objectName: "background"
+ color: "green"
+ width: window.width * window.scaleFactor
+ height: window.height * window.scaleFactor
+ anchors.centerIn: parent
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickapplicationwindow/tst_qquickapplicationwindow.cpp b/tests/auto/quickcontrols/qquickapplicationwindow/tst_qquickapplicationwindow.cpp
index 1d25ffeed6..0b84bca678 100644
--- a/tests/auto/quickcontrols/qquickapplicationwindow/tst_qquickapplicationwindow.cpp
+++ b/tests/auto/quickcontrols/qquickapplicationwindow/tst_qquickapplicationwindow.cpp
@@ -12,6 +12,7 @@
#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
#include <QtQuickTemplates2/private/qquickoverlay_p.h>
#include <QtQuickTemplates2/private/qquickcontrol_p.h>
@@ -53,11 +54,14 @@ private slots:
void componentComplete();
void opacity();
void backgroundSize();
+ void explicitBackgroundSizeBinding();
};
tst_QQuickApplicationWindow::tst_QQuickApplicationWindow()
: QQmlDataTest(QT_QMLTEST_DATADIR)
{
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
QQuickStyle::setStyle("Basic");
}
@@ -982,6 +986,23 @@ void tst_QQuickApplicationWindow::backgroundSize()
QCOMPARE(background->height(), 678);
}
+void tst_QQuickApplicationWindow::explicitBackgroundSizeBinding()
+{
+ QQuickControlsApplicationHelper helper(this, QLatin1String("explicitBackgroundSizeBinding.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *background = window->background();
+ QCOMPARE(background->width(), window->width());
+ QCOMPARE(background->height(), window->height());
+
+ window->setProperty("scaleFactor", 0.5);
+ QCOMPARE(background->width(), window->width() / 2);
+ QCOMPARE(background->height(), window->height() / 2);
+}
+
QTEST_MAIN(tst_QQuickApplicationWindow)
#include "tst_qquickapplicationwindow.moc"
diff --git a/tests/auto/quickcontrols/qquickdrawer/tst_qquickdrawer.cpp b/tests/auto/quickcontrols/qquickdrawer/tst_qquickdrawer.cpp
index 5eb3895849..d16bc7790f 100644
--- a/tests/auto/quickcontrols/qquickdrawer/tst_qquickdrawer.cpp
+++ b/tests/auto/quickcontrols/qquickdrawer/tst_qquickdrawer.cpp
@@ -1055,8 +1055,7 @@ void tst_QQuickDrawer::interactive_data()
void tst_QQuickDrawer::interactive()
{
- if (!(QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation)))
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QFETCH(QString, source);
QQuickControlsApplicationHelper helper(this, source);
diff --git a/tests/auto/quickcontrols/qquickiconlabel/tst_qquickiconlabel.cpp b/tests/auto/quickcontrols/qquickiconlabel/tst_qquickiconlabel.cpp
index 9f0feb5139..c263fbe1bd 100644
--- a/tests/auto/quickcontrols/qquickiconlabel/tst_qquickiconlabel.cpp
+++ b/tests/auto/quickcontrols/qquickiconlabel/tst_qquickiconlabel.cpp
@@ -336,7 +336,7 @@ void tst_qquickiconlabel::iconSourceContext()
QVERIFY(image);
QQuickImagePrivate *imagePrivate
= static_cast<QQuickImagePrivate *>(QQuickItemPrivate::get(image));
- QCOMPARE(imagePrivate->pix.url(), testFileUrl("a.png"));
+ QCOMPARE(imagePrivate->pix1.url(), testFileUrl("a.png"));
}
#endif
}
diff --git a/tests/auto/quickcontrols/qquickmaterialstyle/tst_qquickmaterialstyle.cpp b/tests/auto/quickcontrols/qquickmaterialstyle/tst_qquickmaterialstyle.cpp
index 783c5499c8..48a3e2138a 100644
--- a/tests/auto/quickcontrols/qquickmaterialstyle/tst_qquickmaterialstyle.cpp
+++ b/tests/auto/quickcontrols/qquickmaterialstyle/tst_qquickmaterialstyle.cpp
@@ -2,4 +2,18 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtQuickTest/quicktest.h>
-QUICK_TEST_MAIN(tst_qquickmaterialstyle)
+
+class Setup : public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void applicationAvailable()
+ {
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
+ }
+};
+
+QUICK_TEST_MAIN_WITH_SETUP(tst_qquickmaterialstyle, Setup)
+
+#include "tst_qquickmaterialstyle.moc"
diff --git a/tests/auto/quickcontrols/qquickmenu/data/nativeDynamicSubmenus.qml b/tests/auto/quickcontrols/qquickmenu/data/nativeDynamicSubmenus.qml
new file mode 100644
index 0000000000..951cb7cb6c
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickmenu/data/nativeDynamicSubmenus.qml
@@ -0,0 +1,53 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 400
+ height: 400
+
+ property alias contextMenu: contextMenu
+
+ function addSubMenu(title: string) {
+ contextMenu.addMenu(subMenuComponent.createObject(null, { title: title }))
+ }
+
+ function addAction(menu: T.Menu, text: string) {
+ menu.addAction(actionComponent.createObject(null, { text: text }))
+ }
+
+ function insertAction(menu: T.Menu, index: int, text: string) {
+ menu.insertAction(index, actionComponent.createObject(null, { text: text }))
+ }
+
+ Component {
+ id: actionComponent
+
+ Action {
+ objectName: text
+ }
+ }
+
+ Component {
+ id: subMenuComponent
+
+ Menu {
+ id: subMenu
+ objectName: title
+ popupType: Popup.Native
+
+ Action {
+ text: subMenu.objectName + "Action1"
+ }
+ }
+ }
+
+ Menu {
+ id: contextMenu
+ objectName: "menu"
+ popupType: Popup.Native
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickmenu/data/nativeEmptyMenu.qml b/tests/auto/quickcontrols/qquickmenu/data/nativeEmptyMenu.qml
new file mode 100644
index 0000000000..0ae2c5dc66
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickmenu/data/nativeEmptyMenu.qml
@@ -0,0 +1,51 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 400
+ height: 400
+
+ property alias contextMenu: contextMenu
+
+ function addAction(menu: T.Menu, text: string) {
+ menu.addAction(actionComponent.createObject(null, { text: text }))
+ }
+
+ function insertAction(menu: T.Menu, index: int, text: string) {
+ menu.insertAction(index, actionComponent.createObject(null, { text: text }))
+ }
+
+ function removeAction(menu: T.Menu, index: int) {
+ menu.removeAction(menu.actionAt(index))
+ }
+
+ function addMenu(menu: T.Menu, title: string) {
+ menu.addMenu(menuComponent.createObject(null, { title: title }))
+ }
+
+ Component {
+ id: actionComponent
+
+ Action {
+ objectName: text
+ }
+ }
+
+ Component {
+ id: menuComponent
+
+ Menu {
+ objectName: title
+ }
+ }
+
+ Menu {
+ id: contextMenu
+ objectName: "menu"
+ popupType: Popup.Native
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickmenu/data/nativeMenuSeparator.qml b/tests/auto/quickcontrols/qquickmenu/data/nativeMenuSeparator.qml
new file mode 100644
index 0000000000..54195af349
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickmenu/data/nativeMenuSeparator.qml
@@ -0,0 +1,43 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 400
+ height: 400
+
+ property alias contextMenu: contextMenu
+
+ Menu {
+ id: contextMenu
+ objectName: "menu"
+ popupType: Popup.Native
+
+ Action {
+ objectName: text
+ text: "action1"
+ }
+
+ MenuSeparator {}
+
+ Menu {
+ id: subMenu
+ objectName: "subMenu"
+ popupType: Popup.Native
+
+ Action {
+ objectName: text
+ text: "subAction1"
+ }
+
+ MenuSeparator {}
+
+ Action {
+ objectName: text
+ text: "subAction2"
+ }
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickmenu/data/nativeMixedItems.qml b/tests/auto/quickcontrols/qquickmenu/data/nativeMixedItems.qml
new file mode 100644
index 0000000000..119d8debec
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickmenu/data/nativeMixedItems.qml
@@ -0,0 +1,69 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 400
+ height: 400
+
+ property alias contextMenu: contextMenu
+
+ function insertRectangle(menu: T.Menu, index: int, color: color) {
+ menu.insertItem(index, rectangleComponent.createObject(null, { color: color }))
+ }
+
+ Component {
+ id: rectangleComponent
+
+ Rectangle {
+ objectName: "rectangle"
+ width: 32
+ height: 32
+ }
+ }
+
+ Component {
+ id: menuComponent
+
+ Menu {
+ objectName: title
+ popupType: contextMenu.popupType
+ }
+ }
+
+ Menu {
+ id: contextMenu
+ objectName: "menu"
+ popupType: contextMenu.popupType
+
+ Action {
+ objectName: text
+ text: "action"
+ }
+
+ MenuItem {
+ text: "menuItem"
+ objectName: text
+ }
+
+ Menu {
+ id: subMenu
+ title: "subMenu"
+ objectName: title
+ popupType: contextMenu.popupType
+
+ Action {
+ objectName: text
+ text: "subAction1"
+ }
+
+ Action {
+ objectName: text
+ text: "subAction2"
+ }
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickmenu/data/nativeStatic.qml b/tests/auto/quickcontrols/qquickmenu/data/nativeStatic.qml
new file mode 100644
index 0000000000..32ba1f1829
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickmenu/data/nativeStatic.qml
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 400
+ height: 400
+
+ property alias contextMenu: contextMenu
+
+ Menu {
+ id: contextMenu
+ objectName: "menu"
+ popupType: Popup.Native
+
+ Action {
+ objectName: text
+ text: "action1"
+ shortcut: "A"
+ }
+
+ MenuItem {
+ objectName: text
+ action: Action {
+ text: "menuItemAction"
+ objectName: text
+ shortcut: "B"
+ }
+ }
+
+ Menu {
+ id: subMenu
+ title: "subMenu"
+ objectName: title
+ popupType: Popup.Native
+ // TODO: remove me when the defaults are true
+
+ Action {
+ objectName: text
+ text: "subAction1"
+ shortcut: "1"
+ }
+ }
+ }
+
+ TapHandler {
+ acceptedButtons: Qt.RightButton
+ onTapped: contextMenu.popup()
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp b/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp
index a80aec5ca1..9bbdeb5892 100644
--- a/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp
+++ b/tests/auto/quickcontrols/qquickmenu/tst_qquickmenu.cpp
@@ -9,12 +9,14 @@
#endif
#include <QtGui/qstylehints.h>
#include <QtGui/qpa/qplatformintegration.h>
+#include <QtGui/qpa/qplatformtheme.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlcontext.h>
#include <QtQuick/qquickview.h>
#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <QtQuickControlsTestUtils/private/controlstestutils_p.h>
@@ -26,12 +28,16 @@
#include <QtQuickTemplates2/private/qquickbutton_p.h>
#include <QtQuickTemplates2/private/qquickicon_p.h>
#include <QtQuickTemplates2/private/qquickmenu_p.h>
+#include <QtQuickTemplates2/private/qquickmenu_p_p.h>
#include <QtQuickTemplates2/private/qquickmenuitem_p.h>
#include <QtQuickTemplates2/private/qquickmenuseparator_p.h>
+#include <QtQuickTemplates2/private/qquicknativemenuitem_p.h>
using namespace QQuickVisualTestUtils;
using namespace QQuickControlsTestUtils;
+// Native menu tests are in "nativemenus".
+
class tst_QQuickMenu : public QQmlDataTest
{
Q_OBJECT
@@ -40,6 +46,8 @@ public:
tst_QQuickMenu();
private slots:
+ void init() final;
+
void defaults();
void count();
void mouse();
@@ -55,6 +63,7 @@ private slots:
#if QT_CONFIG(cursor)
void popup();
#endif
+ void openParentlessMenu();
void actions();
#if QT_CONFIG(shortcut)
void actionShortcuts();
@@ -72,6 +81,7 @@ private slots:
void subMenuPosition();
void subMenuWithIcon();
void addRemoveSubMenus();
+ void subMenuPopupType();
void scrollable_data();
void scrollable();
void disableWhenTriggered_data();
@@ -87,19 +97,48 @@ private slots:
void customMenuCullItems();
void customMenuUseRepeaterAsTheContentItem();
void invalidUrlInImgTag();
+ void nativeStatic();
+ void nativeDynamicActions();
+ void nativeDynamicSubmenus();
+ void nativeMenuSeparator();
+ void dontUseNativeMenuWindowsChanges();
+ void nativeMixedItems();
+ void effectivePosition_data();
+ void effectivePosition();
+ void textPadding();
+ void resetCurrentIndexUponPopup_data();
+ void resetCurrentIndexUponPopup();
private:
- static bool hasWindowActivation();
+ bool nativeMenuSupported = false;
+ bool popupWindowsSupported = false;
};
+// This allows us to use QQuickMenuItem's more descriptive operator<< output
+// for the QCOMPARE failure message. It doesn't seem possible to use toString
+// overloads or template specialization when types declared in QML are involved,
+// as is the case for the MenuItems created from Menu's delegate.
+#define COMPARE_MENUITEMS(actualMenuItem, expectedMenuItem) \
+QVERIFY2(actualMenuItem == expectedMenuItem, \
+ qPrintable(QString::fromLatin1("\n Actual: %1\n Expected: %2") \
+ .arg(QDebug::toString(actualMenuItem), QDebug::toString(expectedMenuItem))));
+
tst_QQuickMenu::tst_QQuickMenu()
: QQmlDataTest(QT_QMLTEST_DATADIR)
{
+ std::unique_ptr<QPlatformMenu> platformMenu(QGuiApplicationPrivate::platformTheme()->createPlatformMenu());
+ nativeMenuSupported = platformMenu != nullptr;
+ popupWindowsSupported = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::Capability::MultipleWindows);
}
-bool tst_QQuickMenu::hasWindowActivation()
+void tst_QQuickMenu::init()
{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
+ QQmlDataTest::init();
+
+ // By default we don't want to use native menus, as the majority of the tests
+ // were written before they were a thing. We instead explicitly set it where necessary.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
}
void tst_QQuickMenu::defaults()
@@ -146,8 +185,7 @@ void tst_QQuickMenu::count()
void tst_QQuickMenu::mouse()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
@@ -160,6 +198,7 @@ void tst_QQuickMenu::mouse()
centerOnScreen(window);
moveMouseAway(window);
window->show();
+ window->requestActivate();
QVERIFY(QTest::qWaitForWindowActive(window));
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
@@ -278,8 +317,7 @@ void tst_QQuickMenu::pressAndHold()
void tst_QQuickMenu::contextMenuKeyboard()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
QSKIP("This platform only allows tab focus for text controls");
@@ -468,8 +506,7 @@ void tst_QQuickMenu::contextMenuKeyboard()
// QTBUG-70181
void tst_QQuickMenu::disabledMenuItemKeyNavigation()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
QSKIP("This platform only allows tab focus for text controls");
@@ -535,8 +572,7 @@ void tst_QQuickMenu::disabledMenuItemKeyNavigation()
void tst_QQuickMenu::mnemonics()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
#ifdef Q_OS_MACOS
QSKIP("Mnemonics are not used on macOS");
@@ -593,8 +629,7 @@ void tst_QQuickMenu::mnemonics()
void tst_QQuickMenu::menuButton()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
QSKIP("This platform only allows tab focus for text controls");
@@ -648,8 +683,7 @@ void tst_QQuickMenu::addItem()
void tst_QQuickMenu::menuSeparator()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QLatin1String("menuSeparator.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
@@ -657,6 +691,7 @@ void tst_QQuickMenu::menuSeparator()
centerOnScreen(window);
moveMouseAway(window);
window->show();
+ window->requestActivate();
QVERIFY(QTest::qWaitForWindowActive(window));
QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
@@ -965,6 +1000,29 @@ void tst_QQuickMenu::popup()
}
#endif // QT_CONFIG(cursor)
+void tst_QQuickMenu::openParentlessMenu()
+{
+ // Check that we don't get a crash if the application sets a menu's parentItem
+ // to null. This will also result in the menu not showing at all, since it's
+ // no longer a part of the scene. Even if this limitiation is technically only
+ // relevant for non-native menus, we enforce it also for native menus to ensure
+ // that an application works the same on all platforms.
+ QQuickControlsApplicationHelper helper(this, QLatin1String("popup.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ centerOnScreen(window);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression("cannot show menu: parent is null"));
+
+ QQuickMenu *menu = window->property("menu").value<QQuickMenu *>();
+ QVERIFY(menu);
+ menu->setParentItem(nullptr);
+ menu->popup();
+ QVERIFY(!menu->isVisible());
+}
+
void tst_QQuickMenu::actions()
{
QQuickControlsApplicationHelper helper(this, QLatin1String("actions.qml"));
@@ -1037,13 +1095,13 @@ void tst_QQuickMenu::actions()
#if QT_CONFIG(shortcut)
void tst_QQuickMenu::actionShortcuts()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QLatin1String("actionShortcuts.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
QQuickWindow *window = helper.window;
window->show();
+ window->requestActivate();
QVERIFY(QTest::qWaitForWindowActive(window));
// Try the menu's shortcut.
@@ -1332,8 +1390,7 @@ void tst_QQuickMenu::subMenuKeyboard_data()
void tst_QQuickMenu::subMenuKeyboard()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QFETCH(bool, cascade);
QFETCH(bool, mirrored);
@@ -1344,6 +1401,7 @@ void tst_QQuickMenu::subMenuKeyboard()
centerOnScreen(window);
moveMouseAway(window);
window->show();
+ window->requestActivate();
QVERIFY(QTest::qWaitForWindowActive(window));
if (mirrored) {
@@ -1461,8 +1519,7 @@ void tst_QQuickMenu::subMenuDisabledKeyboard_data()
// QTBUG-69540
void tst_QQuickMenu::subMenuDisabledKeyboard()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QFETCH(bool, cascade);
QFETCH(bool, mirrored);
@@ -1473,6 +1530,7 @@ void tst_QQuickMenu::subMenuDisabledKeyboard()
centerOnScreen(window);
moveMouseAway(window);
window->show();
+ window->requestActivate();
QVERIFY(QTest::qWaitForWindowActive(window));
if (mirrored) {
@@ -1781,6 +1839,92 @@ void tst_QQuickMenu::addRemoveSubMenus()
QVERIFY(subSubMenu1Item.isNull());
}
+void tst_QQuickMenu::subMenuPopupType()
+{
+ // Check that all sub-menus will end up with an effective popup
+ // type equal to the root menu.
+ QQuickControlsApplicationHelper helper(this, QLatin1String("subMenus.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *mainMenu = window->property("mainMenu").value<QQuickMenu *>();
+ auto *subMenu1 = window->property("subMenu1").value<QQuickMenu *>();
+ auto *subSubMenu1 = window->property("subSubMenu1").value<QQuickMenu *>();
+ QVERIFY(mainMenu);
+ QVERIFY(subMenu1);
+ QVERIFY(subSubMenu1);
+ auto *mainMenu_d = QQuickMenuPrivate::get(mainMenu);
+ auto *subMenu1_d = QQuickMenuPrivate::get(subMenu1);
+ auto *subSubMenu1_d = QQuickMenuPrivate::get(subSubMenu1);
+
+ mainMenu->setPopupType(QQuickPopup::Item);
+ QCOMPARE(mainMenu->popupType(), QQuickPopup::Item);
+ mainMenu->open();
+ QTRY_VERIFY(mainMenu->isOpened());
+ QCOMPARE(mainMenu_d->resolvedPopupType(), QQuickPopup::Item);
+ QCOMPARE(subMenu1_d->resolvedPopupType(), QQuickPopup::Item);
+ QCOMPARE(subSubMenu1_d->resolvedPopupType(), QQuickPopup::Item);
+ mainMenu->close();
+ QTRY_VERIFY(!mainMenu->isVisible());
+
+ // Even if we set QQuickPopup::Window as preferred popup type for
+ // subMenu1, the the effective type will still be the same as the
+ // parent menu: QQuickPopup::Item
+ subMenu1->setPopupType(QQuickPopup::Window);
+ QCOMPARE(subMenu1->popupType(), QQuickPopup::Window);
+ QCOMPARE(mainMenu->popupType(), QQuickPopup::Item);
+ mainMenu->open();
+ QTRY_VERIFY(mainMenu->isOpened());
+ QCOMPARE(mainMenu_d->resolvedPopupType(), QQuickPopup::Item);
+ QCOMPARE(subMenu1_d->resolvedPopupType(), QQuickPopup::Item);
+ QCOMPARE(subSubMenu1_d->resolvedPopupType(), QQuickPopup::Item);
+ mainMenu->close();
+ QTRY_VERIFY(!mainMenu->isVisible());
+
+ // Setting QQuickPopup::Window on the root menu will force all sub-menus
+ // to use QQuickPopup::Window as well, if it's supported on the platform
+ // where the test runs. Otherwise it will fall back to QQuickPopup::Item.
+ const QQuickPopup::PopupType windowIfSupportedElseItem =
+ popupWindowsSupported ? QQuickPopup::Window : QQuickPopup::Item;
+ mainMenu->setPopupType(QQuickPopup::Window);
+ QCOMPARE(mainMenu->popupType(), QQuickPopup::Window);
+ QCOMPARE(subMenu1->popupType(), QQuickPopup::Window);
+ mainMenu->open();
+ QTRY_VERIFY(mainMenu->isOpened());
+ QCOMPARE(mainMenu_d->resolvedPopupType(), windowIfSupportedElseItem);
+ QCOMPARE(subMenu1_d->resolvedPopupType(), windowIfSupportedElseItem);
+ QCOMPARE(subSubMenu1_d->resolvedPopupType(), windowIfSupportedElseItem);
+ mainMenu->close();
+ QTRY_VERIFY(!mainMenu->isVisible());
+
+ // Setting QQuickPopup::Native on the root menu will force all sub-menus
+ // to use QQuickPopup::Native as well, if it's supported on the platform
+ // where the test runs. Otherwise it will fall back to either
+ // QQuickPopup::Window or QQuickPopup::Item.
+ mainMenu->setPopupType(QQuickPopup::Native);
+ QCOMPARE(mainMenu->popupType(), QQuickPopup::Native);
+ QCOMPARE(subMenu1->popupType(), QQuickPopup::Window);
+ if (nativeMenuSupported) {
+ // Note that we cannot actually show a native popup while testing, since
+ // that will be a blocking call. Instead we just verify that we
+ // intend to use a native menu.
+ QVERIFY(mainMenu_d->useNativeMenu());
+ QVERIFY(subMenu1_d->useNativeMenu());
+ QVERIFY(subSubMenu1_d->useNativeMenu());
+ } else {
+ // When Native is not supported, we fall back to either Window or Item
+ mainMenu->open();
+ QTRY_VERIFY(mainMenu->isOpened());
+ QCOMPARE(mainMenu_d->resolvedPopupType(), windowIfSupportedElseItem);
+ QCOMPARE(subMenu1_d->resolvedPopupType(), windowIfSupportedElseItem);
+ QCOMPARE(subSubMenu1_d->resolvedPopupType(), windowIfSupportedElseItem);
+ mainMenu->close();
+ QTRY_VERIFY(!mainMenu->isVisible());
+ }
+}
+
void tst_QQuickMenu::scrollable_data()
{
QTest::addColumn<QString>("qmlFilePath");
@@ -2050,13 +2194,13 @@ void tst_QQuickMenu::menuItemWidthAfterRetranslate()
void tst_QQuickMenu::giveMenuItemFocusOnButtonPress()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QLatin1String("giveMenuItemFocusOnButtonPress.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
QQuickApplicationWindow *window = helper.appWindow;
window->show();
+ window->requestActivate();
QVERIFY(QTest::qWaitForWindowActive(window));
// Press enter on the button to open the menu.
@@ -2138,6 +2282,614 @@ void tst_QQuickMenu::invalidUrlInImgTag()
QVERIFY(menuItemFirst);
}
+void tst_QQuickMenu::nativeStatic()
+{
+ QQuickControlsApplicationHelper helper(this, QLatin1String("nativeStatic.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickMenu *contextMenu = window->property("contextMenu").value<QQuickMenu*>();
+ QVERIFY(contextMenu);
+ auto *contextMenuPrivate = QQuickMenuPrivate::get(contextMenu);
+ QVERIFY(contextMenuPrivate->useNativeMenu());
+
+ // Check that the actions of the parent menu can be accessed
+ // and are in the appropriate places in contentModel and contentData.
+ auto *action1 = contextMenu->actionAt(0);
+ QVERIFY(action1);
+ auto *action1MenuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(0));
+ QVERIFY(action1MenuItem);
+ QCOMPARE(action1MenuItem->action(), action1);
+ COMPARE_MENUITEMS(qobject_cast<QQuickMenuItem *>(contextMenuPrivate->contentData.at(0)),
+ action1MenuItem);
+
+ auto *menuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(1));
+ QVERIFY(menuItem);
+ QVERIFY(menuItem->action());
+ QCOMPARE(menuItem->action()->text(), "menuItemAction");
+ COMPARE_MENUITEMS(qobject_cast<QQuickMenuItem *>(contextMenuPrivate->contentData.at(1)), menuItem);
+
+ // Check that the sub-menu can be accessed and is in the
+ // appropriate place in contentData.
+ auto *subMenu = contextMenu->menuAt(2);
+ QVERIFY(subMenu);
+ auto *subMenuPrivate = QQuickMenuPrivate::get(subMenu);
+ auto *subMenuAction1 = subMenu->actionAt(0);
+ QVERIFY(subMenuAction1);
+ auto *subMenuAction1MenuItem = qobject_cast<QQuickMenuItem *>(subMenu->itemAt(0));
+ QVERIFY(subMenuAction1MenuItem);
+ QCOMPARE(subMenuAction1MenuItem->action(), subMenuAction1);
+ COMPARE_MENUITEMS(qobject_cast<QQuickMenuItem *>(subMenuPrivate->contentData.at(0)),
+ subMenuAction1MenuItem);
+}
+
+void tst_QQuickMenu::nativeDynamicActions()
+{
+ QQuickControlsApplicationHelper helper(this, QLatin1String("nativeEmptyMenu.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickMenu *contextMenu = window->property("contextMenu").value<QQuickMenu*>();
+ QVERIFY(contextMenu);
+ auto *contextMenuPrivate = QQuickMenuPrivate::get(contextMenu);
+
+ // Check that items can be appended to an empty menu.
+ QCOMPARE(contextMenu->actionAt(0), nullptr);
+ QVERIFY(QMetaObject::invokeMethod(window, "addAction",
+ Q_ARG(QQuickMenu *, contextMenu), Q_ARG(QString, "action1")));
+ {
+ auto action1 = contextMenu->actionAt(0);
+ QVERIFY(action1);
+ QCOMPARE(action1->text(), "action1");
+ auto *action1MenuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(0));
+ QVERIFY(action1MenuItem);
+ QCOMPARE(action1MenuItem->action(), action1);
+ COMPARE_MENUITEMS(qobject_cast<QQuickMenuItem *>(contextMenuPrivate->contentData.at(0)),
+ action1MenuItem);
+ }
+
+ // Check that actions can be appended after existing items in the parent menu.
+ QCOMPARE(contextMenu->actionAt(1), nullptr);
+ QVERIFY(QMetaObject::invokeMethod(window, "addAction",
+ Q_ARG(QQuickMenu *, contextMenu), Q_ARG(QString, "action2")));
+ {
+ auto action2 = contextMenu->actionAt(1);
+ QVERIFY(action2);
+ QCOMPARE(action2->text(), "action2");
+ auto *action2MenuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(1));
+ QVERIFY(action2MenuItem);
+ QCOMPARE(action2MenuItem->action(), action2);
+ COMPARE_MENUITEMS(qobject_cast<QQuickMenuItem *>(contextMenuPrivate->contentData.at(1)),
+ action2MenuItem);
+ }
+
+ // Check that actions can be inserted before existing items in the parent menu.
+ QVERIFY(QMetaObject::invokeMethod(window, "insertAction",
+ Q_ARG(QQuickMenu *, contextMenu), Q_ARG(int, 0), Q_ARG(QString, "action0")));
+ {
+ auto action0 = contextMenu->actionAt(0);
+ QVERIFY(action0);
+ QCOMPARE(action0->text(), "action0");
+ auto *action0MenuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(0));
+ QVERIFY(action0MenuItem);
+ QCOMPARE(action0MenuItem->action(), action0);
+ // New items are always appended to contentData, regardless of the actual insertion index
+ // in contentModel.
+ COMPARE_MENUITEMS(qobject_cast<QQuickMenuItem *>(contextMenuPrivate->contentData.at(2)),
+ action0MenuItem);
+ }
+}
+
+void tst_QQuickMenu::nativeDynamicSubmenus()
+{
+ QQuickControlsApplicationHelper helper(this, QLatin1String("nativeDynamicSubmenus.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickMenu *contextMenu = window->property("contextMenu").value<QQuickMenu*>();
+ QVERIFY(contextMenu);
+ auto *contextMenuPrivate = QQuickMenuPrivate::get(contextMenu);
+
+ // We construct the sub-menu first in QML. At least on Windows, menu items
+ // added to an empty sub-menu won't show up (tested with Widgets): QTBUG-120494.
+ // So, this adds an already-populated menu as a sub-menu.
+ QVERIFY(QMetaObject::invokeMethod(window, "addSubMenu", Q_ARG(QString, "subMenu1")));
+ auto subMenu1 = contextMenu->menuAt(0);
+ QVERIFY(subMenu1);
+ QCOMPARE(subMenu1->title(), "subMenu1");
+ auto *subMenu1Private = QQuickMenuPrivate::get(subMenu1);
+ if (nativeMenuSupported) {
+ QVERIFY(subMenu1Private->handle);
+ QCOMPARE(subMenu1Private->nativeItems.size(), 1);
+ }
+ auto *subMenu1MenuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(0));
+ QVERIFY(subMenu1MenuItem);
+ COMPARE_MENUITEMS(qobject_cast<QQuickMenuItem *>(contextMenuPrivate->contentData.at(0)),
+ subMenu1MenuItem);
+ QCOMPARE(contextMenuPrivate->contentData.size(), 1);
+ {
+ auto subMenuAction1 = subMenu1->actionAt(0);
+ QVERIFY(subMenuAction1);
+ QCOMPARE(subMenuAction1->text(), "subMenu1Action1");
+ auto *subMenuAction1MenuItem = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(0));
+ QVERIFY(subMenuAction1MenuItem);
+ QCOMPARE(subMenuAction1MenuItem->action(), subMenuAction1);
+ COMPARE_MENUITEMS(qobject_cast<QQuickMenuItem *>(subMenu1Private->contentData.at(0)),
+ subMenuAction1MenuItem);
+ if (nativeMenuSupported)
+ QCOMPARE(subMenu1Private->nativeItems.size(), 1);
+ }
+
+ // Check that actions can be appended after existing items in the sub-menu.
+ QCOMPARE(subMenu1->actionAt(1), nullptr);
+ QVERIFY(QMetaObject::invokeMethod(window, "addAction",
+ Q_ARG(QQuickMenu *, subMenu1), Q_ARG(QString, "subMenu1Action2")));
+ {
+ auto subMenu1Action2 = subMenu1->actionAt(1);
+ QVERIFY(subMenu1Action2);
+ QCOMPARE(subMenu1Action2->text(), "subMenu1Action2");
+ auto *subMenu1Action2MenuItem = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(1));
+ QVERIFY(subMenu1Action2MenuItem);
+ QCOMPARE(subMenu1Action2MenuItem->action(), subMenu1Action2);
+ COMPARE_MENUITEMS(qobject_cast<QQuickMenuItem *>(subMenu1Private->contentData.at(1)),
+ subMenu1Action2MenuItem);
+ QCOMPARE(subMenu1Private->contentData.size(), 2);
+ }
+
+ // Check that actions can be inserted before existing items in the sub-menu.
+ QVERIFY(QMetaObject::invokeMethod(window, "insertAction",
+ Q_ARG(QQuickMenu *, subMenu1), Q_ARG(int, 0), Q_ARG(QString, "subMenu1Action0")));
+ {
+ auto subMenu1Action0 = subMenu1->actionAt(0);
+ QVERIFY(subMenu1Action0);
+ QCOMPARE(subMenu1Action0->text(), "subMenu1Action0");
+ auto *subMenu1Action0MenuItem = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(0));
+ QVERIFY(subMenu1Action0MenuItem);
+ QCOMPARE(subMenu1Action0MenuItem->action(), subMenu1Action0);
+ // New items are always appended to contentData, regardless of the actual insertion index
+ // in contentModel.
+ COMPARE_MENUITEMS(qobject_cast<QQuickMenuItem *>(subMenu1Private->contentData.at(2)),
+ subMenu1Action0MenuItem);
+ QCOMPARE(subMenu1Private->contentData.size(), 3);
+ }
+
+ {
+ // Check that takeMenu works.
+ auto *takenSubMenu = contextMenu->takeMenu(0);
+ QCOMPARE(takenSubMenu, subMenu1);
+ QCOMPARE(contextMenuPrivate->contentData.size(), 0);
+ if (nativeMenuSupported) {
+ QVERIFY(!subMenu1Private->handle);
+ QCOMPARE(subMenu1Private->nativeItems.size(), 0);
+ }
+
+ // Check that the sub-menu can be added back in to the menu.
+ contextMenu->addMenu(takenSubMenu);
+ QCOMPARE(contextMenuPrivate->contentData.size(), 1);
+ auto *subMenu1MenuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(0));
+ QVERIFY(subMenu1MenuItem);
+ QCOMPARE(subMenu1MenuItem->text(), "subMenu1");
+ if (nativeMenuSupported) {
+ QVERIFY(subMenu1Private->handle);
+ QCOMPARE(subMenu1Private->nativeItems.size(), 3);
+ }
+ QCOMPARE(subMenu1Private->contentData.size(), 3);
+
+ auto *subMenu1Action0MenuItem = qobject_cast<QQuickMenuItem *>(subMenu1->itemAt(0));
+ QVERIFY(subMenu1Action0MenuItem);
+ }
+
+ // Check that removeMenu works.
+ QVERIFY(contextMenu->menuAt(0));
+ contextMenu->removeMenu(contextMenu->menuAt(0));
+ QCOMPARE(contextMenuPrivate->contentData.size(), 0);
+}
+
+void tst_QQuickMenu::nativeMenuSeparator()
+{
+ QQuickControlsApplicationHelper helper(this, QLatin1String("nativeMenuSeparator.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ // Check that separators in menus are where we expect them to be.
+ QQuickMenu *contextMenu = window->property("contextMenu").value<QQuickMenu*>();
+ QVERIFY(contextMenu);
+ auto *contextMenuSeparatorAsItem = contextMenu->itemAt(1);
+ QVERIFY(contextMenuSeparatorAsItem);
+ auto *contextMenuSeparator = qobject_cast<QQuickMenuSeparator *>(contextMenuSeparatorAsItem);
+ QVERIFY(contextMenuSeparator);
+ if (nativeMenuSupported) {
+ auto *contextMenuPrivate = QQuickMenuPrivate::get(contextMenu);
+ QCOMPARE(contextMenuPrivate->nativeItems.size(), 3);
+ auto *contextMenuSeparatorNativeItem = contextMenuPrivate->nativeItems.at(1);
+ QVERIFY(contextMenuSeparatorNativeItem);
+ QVERIFY(contextMenuSeparatorNativeItem->separator());
+ }
+
+ // Check that separators in sub-menus are where we expect them to be.
+ QQuickMenu *subMenu = window->property("contextMenu").value<QQuickMenu*>();
+ QVERIFY(subMenu);
+ auto *subMenuSeparatorAsItem = subMenu->itemAt(1);
+ QVERIFY(subMenuSeparatorAsItem);
+ auto *subMenuSeparator = qobject_cast<QQuickMenuSeparator *>(subMenuSeparatorAsItem);
+ QVERIFY(subMenuSeparator);
+ if (nativeMenuSupported) {
+ auto *subMenuPrivate = QQuickMenuPrivate::get(subMenu);
+ QCOMPARE(subMenuPrivate->nativeItems.size(), 3);
+ auto *subMenuSeparatorNativeItem = subMenuPrivate->nativeItems.at(1);
+ QVERIFY(subMenuSeparatorNativeItem);
+ QVERIFY(subMenuSeparatorNativeItem->separator());
+ }
+}
+
+void tst_QQuickMenu::dontUseNativeMenuWindowsChanges()
+{
+ QSKIP("QTBUG-125967 This test will need to be fixed, by using popupType: Popup.Native instead of AA_DontUseNativeMenuWindows.");
+
+ if (QSysInfo::productType() == QLatin1String("b2qt"))
+ QSKIP("b2qt doesn't support native menus");
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows, false);
+ QQuickControlsApplicationHelper helper(this, QLatin1String("nativeStatic.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickMenu *contextMenu = window->property("contextMenu").value<QQuickMenu*>();
+ QVERIFY(contextMenu);
+ QCOMPARE(contextMenu->count(), 3);
+ // Sub-menus should respect the native-ness of their parents.
+ auto *subMenu = contextMenu->menuAt(2);
+ auto *subMenuPrivate = QQuickMenuPrivate::get(subMenu);
+ QVERIFY(subMenuPrivate->useNativeMenu());
+ if (nativeMenuSupported)
+ QVERIFY(subMenuPrivate->handle);
+ else
+ QVERIFY(!subMenuPrivate->handle);
+
+ // Ensure that the menu and its sub-menu have enough room to open.
+ if (window->width() / 2 <= contextMenu->width())
+ window->setWidth(contextMenu->width() * 2 + 1);
+ if (window->height() <= contextMenu->height())
+ window->setHeight(contextMenu->height() + 1);
+ QTRY_COMPARE(window->contentItem()->size(), window->size());
+
+ // We can't test that aboutToShow/aboutToHide is emitted for native menus
+ // because when they are shown, the event loop is blocked until they are closed.
+ // So we just check that a native menu is actually in use before going on to test
+ // non-native menus.
+ auto *contextMenuPrivate = QQuickMenuPrivate::get(contextMenu);
+ if (nativeMenuSupported)
+ QVERIFY(contextMenuPrivate->handle);
+ else
+ QVERIFY(!contextMenuPrivate->handle);
+
+ // We need to wait until the menu is opened before it picks up the changes,
+ // which is why we don't check the native handle here yet.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
+ QVERIFY(!contextMenuPrivate->useNativeMenu());
+ QVERIFY(!subMenuPrivate->useNativeMenu());
+
+ // Check that we can open the menu by right-clicking (or just open it manually
+ // if the platform doesn't support (moving) QCursor).
+ QSignalSpy aboutToShowSpy(contextMenu, &QQuickMenu::aboutToShow);
+ QVERIFY(aboutToShowSpy.isValid());
+ bool couldMoveCursorPos = false;
+ const QPoint cursorPos(1, 1);
+#if QT_CONFIG(cursor)
+ // Try moving the cursor from the current position to test if the platform
+ // supports moving the cursor.
+ const QPoint point = QCursor::pos() + QPoint(1, 1);
+ QCursor::setPos(point);
+ if (QTest::qWaitFor([point]{ return QCursor::pos() == point; })) {
+ couldMoveCursorPos = true;
+ const QPoint globalCursorPos = window->mapToGlobal(cursorPos);
+ QCursor::setPos(globalCursorPos);
+ QTest::mouseClick(window, Qt::RightButton, Qt::NoModifier, cursorPos);
+ }
+#endif
+ if (!couldMoveCursorPos) {
+ contextMenu->setX(cursorPos.x());
+ contextMenu->setY(cursorPos.y());
+ contextMenu->open();
+ }
+ QVERIFY(contextMenu->isVisible());
+ QTRY_VERIFY(contextMenu->isOpened());
+ QCOMPARE(aboutToShowSpy.size(), 1);
+ // Now that it's open and has picked up the changes to Qt::AA_DontUseNativeMenuWindows, we can check it.
+ QVERIFY(!contextMenuPrivate->handle);
+ QVERIFY(!subMenuPrivate->handle);
+ // Check that it opened at the mouse cursor and actually has menu items.
+ QCOMPARE(contextMenu->x(), cursorPos.x());
+ QCOMPARE(contextMenu->y(), cursorPos.y());
+ auto *action1MenuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(0));
+ QVERIFY(action1MenuItem);
+ QCOMPARE(action1MenuItem->text(), "action1");
+
+ // Test setting Qt::AA_DontUseNativeMenuWindows while visible has no effect
+ // (until it's re-opened, which we can't test because we can't test opening native menus).
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows, false);
+ QVERIFY(contextMenuPrivate->useNativeMenu());
+ QVERIFY(!contextMenuPrivate->handle);
+ QVERIFY(!subMenuPrivate->handle);
+
+ // Also check the submenu.
+ auto *subAction1MenuItem = qobject_cast<QQuickMenuItem *>(subMenu->itemAt(0));
+ QVERIFY(subAction1MenuItem);
+ QCOMPARE(subAction1MenuItem->text(), "subAction1");
+
+ // Test closing the non-native menu by clicking on an item.
+ QSignalSpy aboutToHideSpy(contextMenu, &QQuickMenu::aboutToHide);
+ QVERIFY(aboutToHideSpy.isValid());
+ QVERIFY(clickButton(action1MenuItem));
+ QVERIFY(!contextMenu->isOpened());
+ QTRY_VERIFY(!contextMenu->isVisible());
+ QCOMPARE(aboutToShowSpy.size(), 1);
+
+ // Although we can't open the native menu, we can at least check that
+ // attempting (the changes won't come into effect until it's re-opened)
+ // to make the menu native again doesn't e.g. crash.
+ QVERIFY(contextMenuPrivate->useNativeMenu());
+ QVERIFY(subMenuPrivate->useNativeMenu());
+ QVERIFY(!contextMenuPrivate->handle);
+ QVERIFY(!subMenuPrivate->handle);
+}
+
+// Check that non-menu items (e.g. Rectangles) can be inserted between menu items without issues.
+void tst_QQuickMenu::nativeMixedItems()
+{
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows, false);
+ QQuickControlsApplicationHelper helper(this, QLatin1String("nativeMixedItems.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickMenu *contextMenu = window->property("contextMenu").value<QQuickMenu*>();
+ QVERIFY(contextMenu);
+
+ // Insert a Rectangle between the Action and MenuItem in the top-level menu.
+ QVERIFY(QMetaObject::invokeMethod(window, "insertRectangle",
+ Q_ARG(QQuickMenu *, contextMenu), Q_ARG(int, 1), Q_ARG(QColor, QColorConstants::Red)));
+ {
+ auto *action = contextMenu->actionAt(0);
+ QVERIFY(action);
+ QCOMPARE(action->text(), "action");
+ auto *rectangle = qobject_cast<QQuickRectangle *>(contextMenu->itemAt(1));
+ QVERIFY(rectangle);
+ QCOMPARE(rectangle->color(), QColorConstants::Red);
+ auto *menuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(2));
+ QVERIFY(menuItem);
+ QCOMPARE(menuItem->text(), "menuItem");
+ auto *subMenu = contextMenu->menuAt(3);
+ QVERIFY(subMenu);
+ QCOMPARE(subMenu->title(), "subMenu");
+ }
+
+ // Insert a Rectangle at the end of all of the items (which were: {Action, Rectangle, MenuItem, Menu}).
+ QVERIFY(QMetaObject::invokeMethod(window, "insertRectangle",
+ Q_ARG(QQuickMenu *, contextMenu), Q_ARG(int, 4), Q_ARG(QColor, QColorConstants::Blue)));
+ {
+ auto *action = contextMenu->actionAt(0);
+ QVERIFY(action);
+ QCOMPARE(action->text(), "action");
+ auto *rectangle1 = qobject_cast<QQuickRectangle *>(contextMenu->itemAt(1));
+ QVERIFY(rectangle1);
+ QCOMPARE(rectangle1->color(), QColorConstants::Red);
+ auto *menuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(2));
+ QVERIFY(menuItem);
+ QCOMPARE(menuItem->text(), "menuItem");
+ auto *subMenu = contextMenu->menuAt(3);
+ QVERIFY(subMenu);
+ QCOMPARE(subMenu->title(), "subMenu");
+ auto *rectangle2 = qobject_cast<QQuickRectangle *>(contextMenu->itemAt(4));
+ QVERIFY(rectangle2);
+ QCOMPARE(rectangle2->color(), QColorConstants::Blue);
+ }
+
+ // Check that the sub-menu can be accessed and is in the
+ // appropriate place in contentData.
+ auto *subMenu = contextMenu->menuAt(3);
+ QVERIFY(subMenu);
+ // Insert a Rectangle between the Action and MenuItem in the top-level menu.
+ QVERIFY(QMetaObject::invokeMethod(window, "insertRectangle",
+ Q_ARG(QQuickMenu *, subMenu), Q_ARG(int, 1), Q_ARG(QColor, QColorConstants::Green)));
+ {
+ auto *action1 = subMenu->actionAt(0);
+ QVERIFY(action1);
+ QCOMPARE(action1->text(), "subAction1");
+ auto *rectangle = qobject_cast<QQuickRectangle *>(subMenu->itemAt(1));
+ QVERIFY(rectangle);
+ QCOMPARE(rectangle->color(), QColorConstants::Green);
+ auto *action2 = subMenu->actionAt(2);
+ QVERIFY(action2);
+ QCOMPARE(action2->text(), "subAction2");
+ }
+}
+void tst_QQuickMenu::effectivePosition_data()
+{
+ QTest::addColumn<QQuickPopup::PopupType>("popupType");
+
+ QTest::newRow("Item") << QQuickPopup::Item;
+ QTest::newRow("Window") << QQuickPopup::Window;
+}
+
+void tst_QQuickMenu::effectivePosition()
+{
+ // Check that the top-left corner of the background delegate is placed
+ // at the requested menu position. If the popup have negative insets, it
+ // means that the background is drawn outside the bounds of the popup.
+ // To ensure that the whole background still ends up visible on screen, also
+ // when using QQuickPopup::Window, the window will be resized bigger to
+ // encompass both the background and the insets. The window will then be
+ // moved a bit left and up relative to the requested popup position, and the
+ // background the opposite way, to ensure that the top-left of the background
+ // ends up at the requested position.
+ QFETCH(QQuickPopup::PopupType, popupType);
+ SKIP_IF_NO_WINDOW_ACTIVATION
+
+ QQuickControlsApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ QQuickApplicationWindow *window = helper.appWindow;
+ centerOnScreen(window);
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
+ QVERIFY(menu);
+
+ menu->setPopupType(popupType);
+
+ // Move the background delegate a bit out of the popup, to simulate using a drop-shadow.
+ const QPointF insets = QPointF{-20, -10};
+ menu->setLeftInset(insets.x());
+ menu->setTopInset(insets.y());
+
+ const QPointF requestedPos{100, 100};
+ menu->popup(requestedPos);
+ QTRY_VERIFY(menu->isOpened());
+
+ // The logical position of the menu should still be the requested position
+ QTRY_COMPARE(menu->position(), requestedPos);
+ QCOMPARE(menu->x(), requestedPos.x());
+ QCOMPARE(menu->y(), requestedPos.y());
+
+ // But in reality, the background delegate is placed at the
+ // requested position pluss the (negative) insets
+ const auto background = menu->background();
+ QVERIFY(background);
+ const QPointF actualBgPos = background->mapToItem(menu->parentItem(), {0, 0});
+ QCOMPARE(actualBgPos, requestedPos + insets);
+}
+
+void tst_QQuickMenu::textPadding()
+{
+ // Check that you can set implicitTextPadding on each MenuItem, and that
+ // textPadding will end up as the maximum implicitTextPadding among all the
+ // MenuItems in the same Menu.
+
+ QQuickControlsApplicationHelper helper(this, QLatin1String("nativeMixedItems.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickMenu *contextMenu = window->property("contextMenu").value<QQuickMenu*>();
+ QVERIFY(contextMenu);
+ contextMenu->setPopupType(QQuickPopup::Item);
+
+ contextMenu->setVisible(true);
+
+ // Go through all MenuItems, and give them an implicitTextPadding of 0
+ for (int i = 0; i < contextMenu->count(); ++i) {
+ auto menuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(i));
+ QVERIFY(menuItem);
+ menuItem->setImplicitTextPadding(0);
+ QCOMPARE(menuItem->implicitTextPadding(), 0);
+ }
+
+ // Check that all MenuItems now has a textPadding of 0
+ for (int i = 0; i < contextMenu->count(); ++i) {
+ auto menuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(i));
+ QCOMPARE(menuItem->textPadding(), 0);
+ }
+
+ // Let the first MenuItem get a implicitTextPadding of 100. This will
+ // make all MenuItems get a textPadding of 100.
+ auto firstItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(0));
+ firstItem->setImplicitTextPadding(100);
+ QCOMPARE(firstItem->implicitTextPadding(), 100);
+ QCOMPARE(firstItem->textPadding(), 100);
+ for (int i = 1; i < contextMenu->count(); ++i) {
+ auto menuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(i));
+ QCOMPARE(menuItem->implicitTextPadding(), 0);
+ QCOMPARE(menuItem->textPadding(), 100);
+ }
+
+ // Hide the MenuItem with implicitTextPadding set to 100. This
+ // should make all the MenuItems get a textPadding of 0 again.
+ firstItem->setVisible(false);
+ QCOMPARE(firstItem->implicitTextPadding(), 100);
+ for (int i = 0; i < contextMenu->count(); ++i) {
+ auto menuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(i));
+ QCOMPARE(menuItem->textPadding(), 0);
+ }
+
+ // Show it again
+ firstItem->setVisible(true);
+ for (int i = 0; i < contextMenu->count(); ++i) {
+ auto menuItem = qobject_cast<QQuickMenuItem *>(contextMenu->itemAt(i));
+ QCOMPARE(menuItem->textPadding(), 100);
+ }
+}
+
+void tst_QQuickMenu::resetCurrentIndexUponPopup_data()
+{
+ QTest::addColumn<QQuickPopup::PopupType>("popupType");
+
+ QTest::newRow("Item") << QQuickPopup::Item;
+ QTest::newRow("Window") << QQuickPopup::Window;
+
+ // Note: a call to Menu.popup() will be a blocking call on many platforms
+ // when using native menus (e.g macOS and Windows). We can therefore not
+ // check a Menus internal state, nor make a MenuItem current, while it's visible.
+ // QTest::newRow("Native") << QQuickPopup::Native;
+}
+
+void tst_QQuickMenu::resetCurrentIndexUponPopup()
+{
+ // Check that currentIndex is reset back to -1 when
+ // a menu is repopened using the popup() function without
+ // providing a MenuItem as argument.
+ QFETCH(QQuickPopup::PopupType, popupType);
+ SKIP_IF_NO_WINDOW_ACTIVATION
+
+ QQuickControlsApplicationHelper helper(this, QLatin1String("applicationwindow.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ QQuickApplicationWindow *window = helper.appWindow;
+ centerOnScreen(window);
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ QQuickMenu *menu = window->property("menu").value<QQuickMenu*>();
+ QVERIFY(menu);
+
+ menu->setPopupType(popupType);
+
+ QCOMPARE(menu->currentIndex(), -1);
+ QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
+
+ menu->popup();
+ QTRY_VERIFY(menu->isOpened());
+ QCOMPARE(menu->currentIndex(), -1);
+ QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
+
+ menu->setCurrentIndex(1);
+ QCOMPARE(menu->currentIndex(), 1);
+ QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(1));
+
+ menu->close();
+ QTRY_VERIFY(!menu->isVisible());
+
+ menu->popup();
+ QTRY_VERIFY(menu->isOpened());
+ QCOMPARE(menu->currentIndex(), -1);
+ QCOMPARE(menu->contentItem()->property("currentIndex"), QVariant(-1));
+}
+
QTEST_QUICKCONTROLS_MAIN(tst_QQuickMenu)
#include "tst_qquickmenu.moc"
diff --git a/tests/auto/quickcontrols/qquickmenubar/data/hoverAfterClosingWithEscape.qml b/tests/auto/quickcontrols/qquickmenubar/data/hoverAfterClosingWithEscape.qml
index 998a6387dd..3eb41b2501 100644
--- a/tests/auto/quickcontrols/qquickmenubar/data/hoverAfterClosingWithEscape.qml
+++ b/tests/auto/quickcontrols/qquickmenubar/data/hoverAfterClosingWithEscape.qml
@@ -8,10 +8,13 @@ ApplicationWindow {
width: 300
height: 300
- MenuBar {
+ property alias fileMenu: fileMenu
+
+ menuBar: MenuBar {
objectName: "menuBar"
Menu {
+ id: fileMenu
title: qsTr("File")
MenuItem {
diff --git a/tests/auto/quickcontrols/qquickmenubar/data/invaliddelegate.qml b/tests/auto/quickcontrols/qquickmenubar/data/invaliddelegate.qml
new file mode 100644
index 0000000000..4a6272bc47
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickmenubar/data/invaliddelegate.qml
@@ -0,0 +1,40 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: root
+
+ width: 400
+ height: 400
+ visible: true
+
+ menuBar: MenuBar {
+ delegate: Item { /* unsupported since it's not a MenuBarItem */ }
+ Menu {
+ id: fileMenu
+ title: "&File"
+ MenuItem { text: "&Open..." }
+ MenuItem { text: "&Save" }
+ MenuItem { text: "Save &As..." }
+ MenuSeparator { }
+ MenuItem { text: "&Quit" }
+ }
+
+ Menu {
+ title: "&Edit"
+ MenuItem { text: "&Cut" }
+ MenuItem { text: "&Copy" }
+ MenuItem { text: "&Paste" }
+ }
+
+ MenuBarItem {
+ menu: Menu {
+ title: "&Help"
+ MenuItem { text: "&About" }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickmenubar/data/menubarAsHeader.qml b/tests/auto/quickcontrols/qquickmenubar/data/menubarAsHeader.qml
new file mode 100644
index 0000000000..3261ca4b59
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickmenubar/data/menubarAsHeader.qml
@@ -0,0 +1,64 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: root
+ property bool menuBarVisible: true
+ property alias fileMenu: fileMenu
+ property alias contents: contents
+
+ width: 400
+ height: 400
+ visible: true
+
+ header: MenuBar {
+ visible: root.menuBarVisible
+ Menu {
+ id: fileMenu
+ title: "&File"
+ MenuItem { text: "&Open..." }
+ MenuItem { text: "&Save" }
+ MenuItem { text: "Save &As..." }
+ MenuSeparator { }
+ MenuItem { text: "&Quit" }
+ }
+ Menu {
+ title: "&Edit"
+ MenuItem { text: "&Cut" }
+ MenuItem { text: "&Copy" }
+ MenuItem { text: "&Paste" }
+ }
+ Menu {
+ title: "&View"
+ Menu {
+ title: "&Alignment"
+ Menu {
+ title: "&Horizontal"
+ MenuItem { text: "&Left" }
+ MenuItem { text: "&Center" }
+ MenuItem { text: "&Right" }
+ }
+ Menu {
+ title: "&Vertical"
+ MenuItem { text: "&Top" }
+ MenuItem { text: "&Center" }
+ MenuItem { text: "&Bottom" }
+ }
+ }
+ }
+
+ Menu {
+ title: "&Help"
+ MenuItem { text: "&About" }
+ }
+ }
+
+ Rectangle {
+ id: contents
+ anchors.fill: parent
+ color: "green"
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickmenubar/data/menubar.qml b/tests/auto/quickcontrols/qquickmenubar/data/menubaritems.qml
index cf8958e4c4..d7b628afea 100644
--- a/tests/auto/quickcontrols/qquickmenubar/data/menubar.qml
+++ b/tests/auto/quickcontrols/qquickmenubar/data/menubaritems.qml
@@ -5,16 +5,20 @@ import QtQuick
import QtQuick.Controls
ApplicationWindow {
+ id: root
readonly property Button oopsButton: oopsButton
+ property alias fileMenu: fileMenu
width: 400
height: 400
visible: true
- header: MenuBar {
+ menuBar: MenuBar {
MenuBarItem {
menu: Menu {
+ id: fileMenu
title: "&File"
+ objectName: title
MenuItem { text: "&Open..." }
MenuItem { text: "&Save" }
MenuItem { text: "Save &As..." }
@@ -25,6 +29,7 @@ ApplicationWindow {
MenuBarItem {
menu: Menu {
title: "&Edit"
+ objectName: title
MenuItem { text: "&Cut" }
MenuItem { text: "&Copy" }
MenuItem { text: "&Paste" }
@@ -35,14 +40,17 @@ ApplicationWindow {
title: "&View"
Menu {
title: "&Alignment"
+ objectName: title
Menu {
title: "&Horizontal"
+ objectName: title
MenuItem { text: "&Left" }
MenuItem { text: "&Center" }
MenuItem { text: "&Right" }
}
Menu {
title: "&Vertical"
+ objectName: title
MenuItem { text: "&Top" }
MenuItem { text: "&Center" }
MenuItem { text: "&Bottom" }
@@ -54,6 +62,7 @@ ApplicationWindow {
MenuBarItem {
menu: Menu {
title: "&Help"
+ objectName: title
MenuItem { text: "&About" }
}
}
diff --git a/tests/auto/quickcontrols/qquickmenubar/data/menus.qml b/tests/auto/quickcontrols/qquickmenubar/data/menus.qml
new file mode 100644
index 0000000000..947beb50fb
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickmenubar/data/menus.qml
@@ -0,0 +1,85 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: root
+ property bool menuBarVisible: true
+ property alias fileMenu: fileMenu
+ property alias contents: contents
+
+ width: 400
+ height: 400
+ visible: true
+
+ menuBar: MenuBar {
+ visible: root.menuBarVisible
+ Menu {
+ id: fileMenu
+ title: "&File"
+ MenuItem { text: "&Open..." }
+ MenuItem { text: "&Save" }
+ MenuItem { text: "Save &As..." }
+ MenuSeparator { }
+ MenuItem { text: "&Quit" }
+ }
+ Menu {
+ title: "&Edit"
+ MenuItem { text: "&Cut" }
+ MenuItem { text: "&Copy" }
+ MenuItem { text: "&Paste" }
+ }
+ Menu {
+ title: "&View"
+ Menu {
+ title: "&Alignment"
+ Menu {
+ title: "&Horizontal"
+ MenuItem { text: "&Left" }
+ MenuItem { text: "&Center" }
+ MenuItem { text: "&Right" }
+ }
+ Menu {
+ title: "&Vertical"
+ MenuItem { text: "&Top" }
+ MenuItem { text: "&Center" }
+ MenuItem { text: "&Bottom" }
+ }
+ }
+ }
+
+ Menu {
+ title: "&Help"
+ MenuItem { text: "&About" }
+ }
+ }
+
+ Rectangle {
+ id: contents
+ anchors.fill: parent
+ color: "green"
+ }
+
+ Text {
+ // dummy binding to test that fileMenu will be kept alive
+ // after a call to menuBar.removeMenu(fileMenu) followed
+ // by running the garbage collector.
+ text: fileMenu.title
+ }
+
+ Component {
+ id: menuComp
+ Menu {
+ objectName: "Extra"
+ title: "extra"
+ }
+ }
+
+ function addTestMenu()
+ {
+ let menu = menuComp.createObject(null)
+ menuBar.addMenu(menu)
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickmenubar/data/mixed.qml b/tests/auto/quickcontrols/qquickmenubar/data/mixed.qml
new file mode 100644
index 0000000000..25dbf01e15
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickmenubar/data/mixed.qml
@@ -0,0 +1,55 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: root
+ property bool menuBarVisible: true
+ property alias fileMenu: fileMenu
+ property alias contents: contents
+
+ width: 400
+ height: 400
+ visible: true
+
+ menuBar: MenuBar {
+ visible: root.menuBarVisible
+ Menu {
+ id: fileMenu
+ title: "&File"
+ MenuItem { text: "&Open..." }
+ MenuItem { text: "&Save" }
+ MenuItem { text: "Save &As..." }
+ MenuSeparator { }
+ MenuItem { text: "&Quit" }
+ }
+
+ Rectangle {
+ color: "red"
+ width: 100
+ height: 20
+ }
+
+ Menu {
+ title: "&Edit"
+ MenuItem { text: "&Cut" }
+ MenuItem { text: "&Copy" }
+ MenuItem { text: "&Paste" }
+ }
+
+ MenuBarItem {
+ menu: Menu {
+ title: "&Help"
+ MenuItem { text: "&About" }
+ }
+ }
+ }
+
+ Rectangle {
+ id: contents
+ anchors.fill: parent
+ color: "green"
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickmenubar/data/nodelegate.qml b/tests/auto/quickcontrols/qquickmenubar/data/nodelegate.qml
new file mode 100644
index 0000000000..552aea8400
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickmenubar/data/nodelegate.qml
@@ -0,0 +1,40 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: root
+
+ width: 400
+ height: 400
+ visible: true
+
+ menuBar: MenuBar {
+ delegate: null
+ Menu {
+ id: fileMenu
+ title: "&File"
+ MenuItem { text: "&Open..." }
+ MenuItem { text: "&Save" }
+ MenuItem { text: "Save &As..." }
+ MenuSeparator { }
+ MenuItem { text: "&Quit" }
+ }
+
+ Menu {
+ title: "&Edit"
+ MenuItem { text: "&Cut" }
+ MenuItem { text: "&Copy" }
+ MenuItem { text: "&Paste" }
+ }
+
+ MenuBarItem {
+ menu: Menu {
+ title: "&Help"
+ MenuItem { text: "&About" }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickmenubar/data/showandhide.qml b/tests/auto/quickcontrols/qquickmenubar/data/showandhide.qml
new file mode 100644
index 0000000000..fe887c3f99
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickmenubar/data/showandhide.qml
@@ -0,0 +1,40 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: root
+
+ width: 400
+ height: 400
+ visible: true
+
+ menuBar: MenuBar {
+ Menu {
+ title: "Menu1"
+ Action { text: qsTr("Action") }
+ }
+
+ Menu {
+ title: "Menu2"
+ Action { text: qsTr("Action") }
+ }
+
+ MenuBarItem {
+ menu: Menu {
+ title: "Menu3"
+ Action { text: qsTr("Action") }
+ }
+ }
+
+ MenuBarItem {
+ visible: false
+ menu: Menu {
+ title: "Menu4"
+ Action { text: qsTr("Action") }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickmenubar/tst_qquickmenubar.cpp b/tests/auto/quickcontrols/qquickmenubar/tst_qquickmenubar.cpp
index 63dec4dc6a..3f701dc759 100644
--- a/tests/auto/quickcontrols/qquickmenubar/tst_qquickmenubar.cpp
+++ b/tests/auto/quickcontrols/qquickmenubar/tst_qquickmenubar.cpp
@@ -11,7 +11,9 @@
#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
#include <QtQuickTemplates2/private/qquickbutton_p.h>
#include <QtQuickTemplates2/private/qquickmenu_p.h>
+#include <QtQuickTemplates2/private/qquickmenu_p_p.h>
#include <QtQuickTemplates2/private/qquickmenubar_p.h>
+#include <QtQuickTemplates2/private/qquickmenubar_p_p.h>
#include <QtQuickTemplates2/private/qquickmenubaritem_p.h>
#include <QtQuickTemplates2/private/qquickmenuitem_p.h>
#include <QtQuickControlsTestUtils/private/controlstestutils_p.h>
@@ -28,19 +30,54 @@ public:
tst_qquickmenubar();
private slots:
+ void init() override;
void delegate();
+ void mouse_data();
void mouse();
void touch();
+ void keys_data();
void keys();
void mnemonics();
void altNavigation();
+ void addRemove_data();
void addRemove();
+ void addRemoveInlineMenus_data();
+ void addRemoveInlineMenus();
+ void addRemoveMenuFromQml_data();
+ void addRemoveMenuFromQml();
+ void insert_data();
+ void insert();
+ void showAndHideMenuBarItems_data();
+ void showAndHideMenuBarItems();
+ void removeMenuThatIsOpen();
+ void addRemoveExistingMenus_data();
+ void addRemoveExistingMenus();
+ void checkHighlightWhenMenuDismissed_data();
void checkHighlightWhenMenuDismissed();
+ void hoverAfterClosingWithEscape_data();
void hoverAfterClosingWithEscape();
+ void closeByClickingOutside_data();
+ void closeByClickingOutside();
+ void AA_DontUseNativeMenuBar();
+ void containerItems_data();
+ void containerItems();
+ void mixedContainerItems_data();
+ void mixedContainerItems();
+ void applicationWindow_data();
+ void applicationWindow();
+ void menubarAsHeader_data();
+ void menubarAsHeader();
+ void menuPosition();
+ void changeDelegate_data();
+ void changeDelegate();
+ void invalidDelegate_data();
+ void invalidDelegate();
+ void panMenuBar_data();
+ void panMenuBar();
private:
- static bool hasWindowActivation();
-
+ bool nativeMenuBarSupported = false;
+ bool popupWindowsSupported = false;
QScopedPointer<QPointingDevice> touchScreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
};
@@ -53,11 +90,17 @@ tst_qquickmenubar::tst_qquickmenubar()
: QQmlDataTest(QT_QMLTEST_DATADIR)
{
qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+ QQuickMenuBar mb;
+ nativeMenuBarSupported = QQuickMenuBarPrivate::get(&mb)->useNativeMenuBar();
+ popupWindowsSupported = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::Capability::MultipleWindows);
}
-bool tst_qquickmenubar::hasWindowActivation()
+void tst_qquickmenubar::init()
{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
+ // Enable non-native menubars by default.
+ // Note that some tests will set this property to 'true', which
+ // is why we need to set it back to 'false' here.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, false);
}
void tst_qquickmenubar::delegate()
@@ -73,16 +116,27 @@ void tst_qquickmenubar::delegate()
QVERIFY(item);
}
+void tst_qquickmenubar::mouse_data()
+{
+ QTest::addColumn<bool>("usePopupWindow");
+ QTest::newRow("in-scene popup") << false;
+ // Uncomment when popup windows work 100%
+ // if (popupWindowsSupported)
+ // QTest::newRow("popup window") << true;
+}
+
void tst_qquickmenubar::mouse()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
+
+ SKIP_IF_NO_WINDOW_ACTIVATION
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
QSKIP("Mouse highlight not functional on offscreen/minimal platforms");
- QQmlApplicationEngine engine(testFileUrl("menubar.qml"));
+ QQmlApplicationEngine engine(testFileUrl("menubaritems.qml"));
QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
QVERIFY(window);
@@ -91,7 +145,7 @@ void tst_qquickmenubar::mouse()
moveMouseAway(window.data());
QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>();
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
QVERIFY(menuBar);
QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0);
@@ -260,6 +314,8 @@ void tst_qquickmenubar::mouse()
// - It's what happens with e.g. overflow menus on Android.
void tst_qquickmenubar::touch()
{
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
QQuickControlsApplicationHelper helper(this, QLatin1String("touch.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
centerOnScreen(helper.window);
@@ -285,12 +341,23 @@ void tst_qquickmenubar::touch()
QTRY_VERIFY(fileMenuBarMenu->isOpened());
}
+void tst_qquickmenubar::keys_data()
+{
+ QTest::addColumn<bool>("usePopupWindow");
+ QTest::newRow("in-scene popup") << false;
+ // Uncomment when popup windows work 100%
+ // if (popupWindowsSupported)
+ // QTest::newRow("popup window") << true;
+}
+
void tst_qquickmenubar::keys()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
+
+ SKIP_IF_NO_WINDOW_ACTIVATION
- QQmlApplicationEngine engine(testFileUrl("menubar.qml"));
+ QQmlApplicationEngine engine(testFileUrl("menubaritems.qml"));
QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
QVERIFY(window);
@@ -299,7 +366,7 @@ void tst_qquickmenubar::keys()
moveMouseAway(window.data());
QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>();
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
QVERIFY(menuBar);
QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0);
@@ -479,14 +546,16 @@ void tst_qquickmenubar::keys()
void tst_qquickmenubar::mnemonics()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
+
+ SKIP_IF_NO_WINDOW_ACTIVATION
#if defined(Q_OS_MACOS) or defined(Q_OS_WEBOS)
QSKIP("Mnemonics are not used on this platform");
#endif
- QQmlApplicationEngine engine(testFileUrl("menubar.qml"));
+ QQmlApplicationEngine engine(testFileUrl("menubaritems.qml"));
QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
QVERIFY(window);
@@ -497,7 +566,7 @@ void tst_qquickmenubar::mnemonics()
MnemonicKeySimulator keySim(window.data());
- QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>();
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
QVERIFY(menuBar);
QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0);
@@ -632,10 +701,12 @@ void tst_qquickmenubar::mnemonics()
void tst_qquickmenubar::altNavigation()
{
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
if (!QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::MenuBarFocusOnAltPressRelease).toBool())
QSKIP("Menu doesn't get focus via Alt press&release on this platform");
- QQmlApplicationEngine engine(testFileUrl("menubar.qml"));
+ QQmlApplicationEngine engine(testFileUrl("menubaritems.qml"));
QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
QVERIFY(window);
@@ -644,7 +715,7 @@ void tst_qquickmenubar::altNavigation()
moveMouseAway(window.data());
QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>();
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
QVERIFY(menuBar);
QQuickMenu *fileMenuBarMenu = menuBar->menuAt(0);
@@ -669,12 +740,30 @@ void tst_qquickmenubar::altNavigation()
QVERIFY(editMenuBarMenu->hasActiveFocus());
}
+void tst_qquickmenubar::addRemove_data()
+{
+ QTest::addColumn<QString>("testUrl");
+ QTest::addColumn<bool>("native");
+ QTest::newRow("menuitems, not native") << QStringLiteral("empty.qml") << false;
+ if (nativeMenuBarSupported)
+ QTest::newRow("menuitems, native") << QStringLiteral("empty.qml") << true;
+}
+
void tst_qquickmenubar::addRemove()
{
- QQmlApplicationEngine engine(testFileUrl("empty.qml"));
+ QFETCH(QString, testUrl);
+ QFETCH(bool, native);
- QScopedPointer<QQuickMenuBar> menuBar(qobject_cast<QQuickMenuBar *>(engine.rootObjects().value(0)));
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, !native);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl(testUrl));
+
+ QQuickMenuBar *menuBar = qobject_cast<QQuickMenuBar *>(engine.rootObjects().value(0));
QVERIFY(menuBar);
+ QQuickMenuBarPrivate *menuBarPrivate = QQuickMenuBarPrivate::get(menuBar);
+ QCOMPARE(menuBarPrivate->useNativeMenuBar(), native);
+ if (native)
+ QVERIFY(menuBarPrivate->nativeHandle());
QQmlComponent component(&engine);
component.setData("import QtQuick.Controls; Menu { }", QUrl());
@@ -690,7 +779,7 @@ void tst_qquickmenubar::addRemove()
QCOMPARE(menuBarItem1->menu(), menu1.data());
QCOMPARE(menuBar->itemAt(0), menuBarItem1.data());
- QScopedPointer<QQuickMenu> menu2(qobject_cast<QQuickMenu *>(component.create()));
+ QPointer<QQuickMenu> menu2(qobject_cast<QQuickMenu *>(component.create()));
QVERIFY(!menu2.isNull());
menuBar->insertMenu(0, menu2.data());
QCOMPARE(menuBar->count(), 2);
@@ -703,15 +792,26 @@ void tst_qquickmenubar::addRemove()
QCOMPARE(menuBar->itemAt(0), menuBarItem2.data());
QCOMPARE(menuBar->itemAt(1), menuBarItem1.data());
- // takeMenu(int) does not destroy the menu, but does destroy the respective item in the menubar
+ // takeMenu(int) does not explicitly destroy the menu, but leave
+ // this to the garbage collector. The MenuBarItem, OTOH, is currently
+ // being destroyed from c++, but this might change in the future.
QCOMPARE(menuBar->takeMenu(1), menu1.data());
QCOMPARE(menuBar->count(), 1);
QVERIFY(!menuBar->menuAt(1));
QVERIFY(!menuBar->itemAt(1));
- QCoreApplication::sendPostedEvents(menu1.data(), QEvent::DeferredDelete);
+ QTRY_VERIFY(menuBarItem1.isNull());
+ QVERIFY(!menu1.isNull());
+ gc(engine);
QVERIFY(!menu1.isNull());
- QCoreApplication::sendPostedEvents(menuBarItem1, QEvent::DeferredDelete);
- QVERIFY(menuBarItem1.isNull());
+
+ // check that it's safe to call takeMenu(int) with
+ // an index that is out of range.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*out of range"));
+ QCOMPARE(menuBar->takeMenu(-1), nullptr);
+ QCOMPARE(menuBar->count(), 1);
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*out of range"));
+ QCOMPARE(menuBar->takeMenu(10), nullptr);
+ QCOMPARE(menuBar->count(), 1);
// addMenu(Menu) re-creates the respective item in the menubar
menuBar->addMenu(menu1.data());
@@ -719,18 +819,295 @@ void tst_qquickmenubar::addRemove()
menuBarItem1 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(1));
QVERIFY(!menuBarItem1.isNull());
- // removeMenu(Menu) destroys both the menu and the respective item in the menubar
+ // removeMenu(menu) does not explicitly destroy the menu, but leave
+ // this to the garbage collector. The MenuBarItem, OTOH, is currently
+ // being destroyed from c++, but this might change in the future.
menuBar->removeMenu(menu1.data());
QCOMPARE(menuBar->count(), 1);
QVERIFY(!menuBar->itemAt(1));
- QCoreApplication::sendPostedEvents(menu1.data(), QEvent::DeferredDelete);
- QVERIFY(menu1.isNull());
- QCoreApplication::sendPostedEvents(menuBarItem1, QEvent::DeferredDelete);
- QVERIFY(menuBarItem1.isNull());
+ QTRY_VERIFY(menuBarItem1.isNull());
+ QVERIFY(!menu1.isNull());
+ gc(engine);
+ QVERIFY(!menu1.isNull());
+}
+
+void tst_qquickmenubar::addRemoveInlineMenus_data()
+{
+ QTest::addColumn<bool>("native");
+ QTest::newRow("not native") << false;
+ if (nativeMenuBarSupported)
+ QTest::newRow("native") << true;
+}
+
+void tst_qquickmenubar::addRemoveInlineMenus()
+{
+ // Check that it's safe to remove a menu from the menubar, that
+ // is an inline child from QML (fileMenu). Since it's owned by
+ // JavaScript, it should be deleted by the gc when appropriate, and
+ // not upon a call to removeMenu.
+ QFETCH(bool, native);
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, !native);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("menus.qml"));
+
+ auto window = qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0));
+ QVERIFY(window);
+ auto menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+
+ QPointer<QQuickMenu> fileMenu = window->property("fileMenu").value<QQuickMenu *>();
+ QVERIFY(fileMenu);
+ QCOMPARE(menuBar->menuAt(0), fileMenu);
+
+ QPointer<QQuickItem> menuBarItem = menuBar->itemAt(0);
+ QVERIFY(menuBarItem);
+
+ menuBar->removeMenu(fileMenu);
+ QVERIFY(menuBar->menuAt(0) != fileMenu);
+ QTRY_VERIFY(!menuBarItem);
+ QVERIFY(fileMenu);
+ gc(engine);
+ QVERIFY(fileMenu);
+
+ // Add it back again, but to the end. This should also be fine, even
+ // if it no longer matches the initial order in the QML file.
+ menuBar->addMenu(fileMenu);
+ QVERIFY(fileMenu);
+ QCOMPARE(menuBar->menuAt(menuBar->count() - 1), fileMenu);
+}
+
+void tst_qquickmenubar::addRemoveMenuFromQml_data()
+{
+ QTest::addColumn<bool>("native");
+ QTest::newRow("not native") << false;
+ if (nativeMenuBarSupported)
+ QTest::newRow("native") << true;
+}
+
+void tst_qquickmenubar::addRemoveMenuFromQml()
+{
+ // Create a menu dynamically from QML, and add it to
+ // the menubar. Remove it again. Check that the
+ // garbage collector will then destruct it.
+ QFETCH(bool, native);
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, !native);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("menus.qml"));
+
+ auto window = qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0));
+ QVERIFY(window);
+ auto menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+
+ const int initialMenuCount = menuBar->count();
+ QVERIFY(initialMenuCount > 0);
+
+ QMetaObject::invokeMethod(window, "addTestMenu");
+
+ QCOMPARE(menuBar->count(), initialMenuCount + 1);
+
+ // The "extra" menu should have been added to
+ // the end of the menu bar. Verify this.
+ QQuickItem *item = menuBar->itemAt(menuBar->count() - 1);
+ QPointer<QQuickMenuBarItem> menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
+ QVERIFY(menuBarItem);
+ QPointer<QQuickMenu> menu = menuBar->menuAt(menuBar->count() - 1);
+ QVERIFY(menu);
+ QCOMPARE(menu->title(), "extra");
+ QCOMPARE(menuBarItem->menu(), menu);
+
+ // Remove the menu again. Since we have no other references to
+ // it from QML, it should be collected by the gc.
+ menuBar->removeMenu(menu);
+ QCOMPARE(menuBar->count(), initialMenuCount);
+ QTRY_VERIFY(!menuBarItem);
+ QVERIFY(menu);
+ gc(engine);
+ QVERIFY(!menu);
+}
+
+void tst_qquickmenubar::insert_data()
+{
+ QTest::addColumn<bool>("native");
+ QTest::newRow("not native") << false;
+ if (nativeMenuBarSupported)
+ QTest::newRow("native") << true;
+}
+
+void tst_qquickmenubar::insert()
+{
+ QFETCH(bool, native);
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, !native);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("menus.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+
+ const int initialMenuCount = menuBar->count();
+ QVERIFY(initialMenuCount > 0);
+
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick.Controls; Menu { }", QUrl());
+
+ QPointer<QQuickMenu> menu1(qobject_cast<QQuickMenu *>(component.create()));
+ QVERIFY(!menu1.isNull());
+ menuBar->insertMenu(0, menu1.data());
+ QCOMPARE(menuBar->count(), initialMenuCount + 1);
+ QCOMPARE(menuBar->menuAt(0), menu1.data());
+
+ QPointer<QQuickMenu> menu2(qobject_cast<QQuickMenu *>(component.create()));
+ QVERIFY(!menu2.isNull());
+ menuBar->insertMenu(2, menu2.data());
+ QCOMPARE(menuBar->count(), initialMenuCount + 2);
+ QCOMPARE(menuBar->menuAt(2), menu2.data());
+}
+
+void tst_qquickmenubar::showAndHideMenuBarItems_data()
+{
+ QTest::addColumn<bool>("native");
+ QTest::newRow("not native") << false;
+ if (nativeMenuBarSupported)
+ QTest::newRow("native") << true;
+}
+
+void tst_qquickmenubar::showAndHideMenuBarItems()
+{
+ // Check that you can toggle MenuBarItem.visible to show and hide menus in the
+ // menu bar. Note that this is not the same as setting Menu.visible, which will
+ // instead open or close the menus.
+ QFETCH(bool, native);
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, !native);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("showandhide.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+ QCOMPARE(menuBar->count(), 4);
+
+ auto menuBarItem0 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(0));
+ auto menuBarItem1 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(1));
+ auto menuBarItem2 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(2));
+ auto menuBarItem3 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(3));
+
+ // Initially, the three first MenuBarItems are visible, but the 4th is hidden
+ QVERIFY(menuBarItem0->isVisible());
+ QVERIFY(menuBarItem1->isVisible());
+ QVERIFY(menuBarItem2->isVisible());
+ QVERIFY(!menuBarItem3->isVisible());
+
+ // Native and visible QQuickMenus should be backed by
+ // QPlatformMenus. Otherwise the handle should be nullptr.
+ QCOMPARE(bool(QQuickMenuPrivate::get(menuBarItem0->menu())->maybeNativeHandle()), native);
+ QCOMPARE(bool(QQuickMenuPrivate::get(menuBarItem1->menu())->maybeNativeHandle()), native);
+ QCOMPARE(bool(QQuickMenuPrivate::get(menuBarItem2->menu())->maybeNativeHandle()), native);
+ QVERIFY(!QQuickMenuPrivate::get(menuBarItem3->menu())->maybeNativeHandle());
+
+ // Make the hidden MenuBarItem visible
+ menuBarItem3->setVisible(true);
+ QCOMPARE(bool(QQuickMenuPrivate::get(menuBarItem3->menu())->maybeNativeHandle()), native);
+ QCOMPARE(menuBar->count(), 4);
+ // Hide it again
+ menuBarItem3->setVisible(false);
+ QVERIFY(!QQuickMenuPrivate::get(menuBarItem3->menu())->maybeNativeHandle());
+ QCOMPARE(menuBar->count(), 4);
+
+ // Toggle the visibility of a MenuBarItem created from the
+ // delegate, which is also initially visible.
+ menuBarItem0->setVisible(false);
+ QVERIFY(!QQuickMenuPrivate::get(menuBarItem0->menu())->maybeNativeHandle());
+ QCOMPARE(menuBar->count(), 4);
+ // Hide it again
+ menuBarItem0->setVisible(true);
+ QCOMPARE(bool(QQuickMenuPrivate::get(menuBarItem0->menu())->maybeNativeHandle()), native);
+ QCOMPARE(menuBar->count(), 4);
+}
+
+void tst_qquickmenubar::removeMenuThatIsOpen()
+{
+ // Check that if we remove a menu that is open, it ends
+ // up being hidden / closed. This is mostly important for
+ // non-native menubars.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("menus.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+
+ QQuickMenu *fileMenu = window->property("fileMenu").value<QQuickMenu *>();
+ QVERIFY(fileMenu);
+ fileMenu->open();
+ QVERIFY(fileMenu->isVisible());
+ menuBar->removeMenu(fileMenu);
+ QVERIFY(fileMenu);
+ QTRY_VERIFY(!fileMenu->isVisible());
+}
+
+void tst_qquickmenubar::addRemoveExistingMenus_data()
+{
+ QTest::addColumn<bool>("native");
+ QTest::addColumn<bool>("usePopupWindow");
+ QTest::newRow("non-native, in-scene") << false << false;
+ if (nativeMenuBarSupported)
+ QTest::newRow("native, native") << true << true;
+ // Uncomment when popup windows work 100%
+ // if (popupWindowsSupported)
+ // QTest::newRow("non-native, popup window") << false << true;
+}
+
+void tst_qquickmenubar::addRemoveExistingMenus()
+{
+ // Check that you get warnings if trying to add menus that
+ // are already in the menubar, or remove menus that are not.
+ QFETCH(bool, native);
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, !native);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("menus.qml"));
+
+ auto window = qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0));
+ QVERIFY(window);
+ auto menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+
+ QPointer<QQuickMenu> fileMenu = window->property("fileMenu").value<QQuickMenu *>();
+ QVERIFY(fileMenu);
+ QCOMPARE(menuBar->menuAt(0), fileMenu);
+
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression("cannot add menu.*"));
+ menuBar->addMenu(fileMenu);
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression("cannot insert menu.*"));
+ menuBar->insertMenu(0, fileMenu);
+ menuBar->removeMenu(fileMenu);
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression("cannot remove menu.*"));
+ menuBar->removeMenu(fileMenu);
+}
+
+void tst_qquickmenubar::checkHighlightWhenMenuDismissed_data()
+{
+ QTest::addColumn<bool>("usePopupWindow");
+ QTest::newRow("in-scene popup") << false;
+ // Uncomment when popup windows work 100%
+ // if (popupWindowsSupported)
+ // QTest::newRow("popup window") << true;
}
void tst_qquickmenubar::checkHighlightWhenMenuDismissed()
{
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
QSKIP("Mouse highlight not functional on offscreen/minimal platforms");
@@ -787,8 +1164,19 @@ void tst_qquickmenubar::checkHighlightWhenMenuDismissed()
QVERIFY(!dynamicMenuBarItem->isHighlighted());
}
+void tst_qquickmenubar::hoverAfterClosingWithEscape_data()
+{
+ QTest::addColumn<bool>("usePopupWindow");
+ QTest::newRow("in-scene popup") << false;
+ // Uncomment when popup windows work 100%
+ // if (popupWindowsSupported)
+ // QTest::newRow("popup window") << true;
+}
+
void tst_qquickmenubar::hoverAfterClosingWithEscape()
{
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
QSKIP("Mouse highlight not functional on offscreen/minimal platforms");
@@ -821,6 +1209,576 @@ void tst_qquickmenubar::hoverAfterClosingWithEscape()
QVERIFY(!secondMenu->isVisible());
}
+void tst_qquickmenubar::closeByClickingOutside_data()
+{
+ QTest::addColumn<QQuickPopup::PopupType>("popupType");
+
+ QTest::newRow("Item") << QQuickPopup::Item;
+ QTest::newRow("Window") << QQuickPopup::Window;
+}
+
+void tst_qquickmenubar::closeByClickingOutside()
+{
+ QFETCH(QQuickPopup::PopupType, popupType);
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QSKIP("Mouse highlight not functional on offscreen/minimal platforms");
+
+ QQuickControlsApplicationHelper helper(this, QLatin1String("hoverAfterClosingWithEscape.qml"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickApplicationWindow *window = helper.appWindow;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *menuBar = window->property("menuBar").value<QQuickMenuBar*>();
+ QVERIFY(menuBar);
+ auto *fileMenu = window->property("fileMenu").value<QQuickMenu*>();
+ QVERIFY(fileMenu);
+ auto *firstMenuBarItem(qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(0)));
+ QVERIFY(firstMenuBarItem);
+
+ fileMenu->setPopupType(popupType);
+
+ // Open the first menu by clicking on the first menu bar item.
+ QVERIFY(clickButton(firstMenuBarItem));
+ QTRY_VERIFY(fileMenu->isOpened());
+ // Check that the first menu bar item stays highlighted
+ QVERIFY(firstMenuBarItem->isHighlighted());
+ // ...also after we move the mouse away from it
+ const QPoint windowCenter = {window->width() / 2, window->height() / 2};
+ QTest::mouseMove(window, windowCenter);
+ QVERIFY(firstMenuBarItem->isHighlighted());
+ // Close the menu with by clicking outside of it
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, windowCenter);
+ QTRY_VERIFY(!fileMenu->isVisible());
+ // Check that firstMenuBarItem is no longer highlighted since it's
+ // no longer hovered, and the menu it represents is closed.
+ QVERIFY(!firstMenuBarItem->isHighlighted());
+}
+
+void tst_qquickmenubar::AA_DontUseNativeMenuBar()
+{
+ // Check that we end up with a non-native menu bar when AA_DontUseNativeMenuBar is set.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("menus.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+ auto menuBarPrivate = QQuickMenuBarPrivate::get(menuBar);
+ QQuickItem *contents = window->property("contents").value<QQuickItem *>();
+ QVERIFY(contents);
+
+ QVERIFY(!menuBarPrivate->nativeHandle());
+ QVERIFY(menuBar->isVisible());
+ QVERIFY(menuBar->count() > 0);
+ QVERIFY(menuBar->height() > 0);
+ QCOMPARE(contents->height(), window->height() - menuBar->height());
+
+ // If the menu bar is not native, the menus should not be native either.
+ // The main reason for this limitation is that a native menu typically
+ // run in separate native event loop which will not forward mouse events
+ // to Qt. And this is needed for a non-native menu bar to work (e.g to
+ // support hovering over the menu bar items to open and close menus).
+ const auto firstMenu = menuBar->menuAt(0);
+ QVERIFY(firstMenu);
+ QVERIFY(!QQuickMenuPrivate::get(firstMenu)->maybeNativeHandle());
+}
+
+void tst_qquickmenubar::containerItems_data()
+{
+ QTest::addColumn<QString>("testUrl");
+ QTest::addColumn<bool>("native");
+ QTest::newRow("menuitems, not native") << QStringLiteral("menubaritems.qml") << false;
+ QTest::newRow("menus, not native") << QStringLiteral("menus.qml") << false;
+ if (nativeMenuBarSupported) {
+ QTest::newRow("menuitems, native") << QStringLiteral("menubaritems.qml") << true;
+ QTest::newRow("menus, native") << QStringLiteral("menus.qml") << true;
+ }
+}
+
+void tst_qquickmenubar::containerItems()
+{
+ // Check that the MenuBar ends up containing a MenuBarItem
+ // for each Menu added. This should be the case regardless of
+ // if the MenuBar is native or not. There are several ways
+ // of accessing those MenuBarItems and menus in the MenuBar
+ // API, so check that all end up in sync.
+ QFETCH(QString, testUrl);
+ QFETCH(bool, native);
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, !native);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl(testUrl));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+ auto *menuBarPrivate = QQuickMenuBarPrivate::get(menuBar);
+ QCOMPARE(menuBarPrivate->useNativeMenuBar(), native);
+
+ QCOMPARE(menuBar->count(), 4);
+ for (int i = 0; i < menuBar->count(); ++i) {
+ QQuickMenu *menu = menuBar->menuAt(i);
+ QVERIFY(menu);
+
+ // Test the itemAt() API
+ QQuickItem *item = menuBar->itemAt(i);
+ QVERIFY(item);
+ auto menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
+ QVERIFY(menuBarItem);
+ QCOMPARE(menuBarItem->menu(), menu);
+
+ // Test the "contentData" list property API
+ auto cd = menuBarPrivate->contentData();
+ QCOMPARE(cd.count(&cd), menuBar->count());
+ auto cdItem = static_cast<QQuickItem *>(cd.at(&cd, i));
+ QVERIFY(cdItem);
+ auto cdMenuBarItem = qobject_cast<QQuickMenuBarItem *>(cdItem);
+ QVERIFY(cdMenuBarItem);
+ QCOMPARE(cdMenuBarItem->menu(), menu);
+
+ // Test the "menus" list property API
+ auto menus = QQuickMenuBarPrivate::get(menuBar)->menus();
+ QCOMPARE(menus.count(&menus), menuBar->count());
+ auto menusMenu = menus.at(&menus, i);
+ QVERIFY(menusMenu);
+ QCOMPARE(menusMenu, menu);
+ }
+}
+
+void tst_qquickmenubar::mixedContainerItems_data()
+{
+ QTest::addColumn<bool>("native");
+ QTest::newRow("not native") << false;
+ if (nativeMenuBarSupported)
+ QTest::newRow("native") << true;
+}
+
+void tst_qquickmenubar::mixedContainerItems()
+{
+ // The application is allowed to add items other
+ // than MenuBarItems and Menus as children. But those
+ // should just be ignored by the MenuBar (and the Container).
+ QFETCH(bool, native);
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, !native);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("mixed.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+
+ // The menubar has four children, but only three of them are
+ // Menus and MenuBarItems. So we should therefore only end up
+ // with three menus in the MenuBar, and three items in the Container.
+ QCOMPARE(menuBar->count(), 3);
+ for (int i = 0; i < 3; ++i) {
+ auto item = menuBar->itemAt(i);
+ QVERIFY(item);
+ auto menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
+ QVERIFY(menuBarItem);
+ QCOMPARE(menuBarItem->menu(), menuBar->menuAt(i));
+ }
+
+ // Try to add an unsupported item dynamically. It should
+ // have no impact on the MenuBar/Container API.
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick; Item { }", QUrl());
+ QPointer<QQuickItem> plainItem(qobject_cast<QQuickItem *>(component.create()));
+ QVERIFY(plainItem);
+
+ menuBar->addItem(plainItem);
+ QCOMPARE(menuBar->count(), 3);
+ for (int i = 0; i < 3; ++i) {
+ auto item = menuBar->itemAt(i);
+ QVERIFY(item);
+ auto menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
+ QVERIFY(menuBarItem);
+ QCOMPARE(menuBarItem->menu(), menuBar->menuAt(i));
+ }
+
+ // Remove it again. It should have no impact on
+ // the MenuBar/Container API.
+ menuBar->removeItem(plainItem);
+ QCOMPARE(menuBar->count(), 3);
+ for (int i = 0; i < 3; ++i) {
+ auto item = menuBar->itemAt(i);
+ QVERIFY(item);
+ auto menuBarItem = qobject_cast<QQuickMenuBarItem *>(item);
+ QVERIFY(menuBarItem);
+ QCOMPARE(menuBarItem->menu(), menuBar->menuAt(i));
+ }
+}
+
+void tst_qquickmenubar::applicationWindow_data()
+{
+ QTest::addColumn<bool>("initiallyNative");
+ QTest::addColumn<bool>("initiallyVisible");
+ QTest::newRow("initially not native, visible") << false << true;
+ QTest::newRow("initially not native, hidden") << false << false;
+ if (nativeMenuBarSupported) {
+ QTest::newRow("initially native, visible") << true << true;
+ QTest::newRow("initially native, hidden") << true << false;
+ }
+}
+
+void tst_qquickmenubar::applicationWindow()
+{
+ // Check that ApplicationWindow adds or removes the non-native
+ // menubar in response to toggling Qt::AA_DontUseNativeMenuBar and
+ // MenuBar.visible.
+ QFETCH(bool, initiallyNative);
+ QFETCH(bool, initiallyVisible);
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, !initiallyNative);
+ QQmlApplicationEngine engine;
+ engine.setInitialProperties({{ "visible", initiallyVisible }});
+ engine.load(testFileUrl("menus.qml"));
+
+ QPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+ auto menuBarPrivate = QQuickMenuBarPrivate::get(menuBar);
+ QQuickItem *contents = window->property("contents").value<QQuickItem *>();
+ QVERIFY(contents);
+
+ for (const bool visible : {initiallyVisible, !initiallyVisible, initiallyVisible}) {
+ menuBar->setVisible(visible);
+
+ const bool nativeMenuBarVisible = bool(menuBarPrivate->nativeHandle());
+ QCOMPARE(nativeMenuBarVisible, initiallyNative && visible);
+
+ if (!visible) {
+ QVERIFY(!menuBar->isVisible());
+ QVERIFY(!nativeMenuBarVisible);
+ QCOMPARE(contents->height(), window->height());
+ } else if (nativeMenuBarVisible) {
+ QVERIFY(menuBar->isVisible());
+ QCOMPARE(contents->height(), window->height());
+ } else {
+ QVERIFY(menuBar->isVisible());
+ QVERIFY(menuBar->height() > 0);
+ QCOMPARE(contents->height(), window->height() - menuBar->height());
+ }
+ }
+}
+
+void tst_qquickmenubar::menubarAsHeader_data()
+{
+ QTest::addColumn<bool>("native");
+ QTest::newRow("not native") << false;
+ if (nativeMenuBarSupported)
+ QTest::newRow("native") << true;
+}
+
+void tst_qquickmenubar::menubarAsHeader()
+{
+ // ApplicationWindow.menuBar was added in Qt 5.10. Before that
+ // the menuBar was supposed to be assigned to ApplicationWindow.header.
+ // For backwards compatibility, check that you can still do that.
+ QFETCH(bool, native);
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, !native);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("menubarAsHeader.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QQuickMenuBar *menuBar = window->property("header").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+ auto menuBarPrivate = QQuickMenuBarPrivate::get(menuBar);
+ QQuickItem *contents = window->property("contents").value<QQuickItem *>();
+ QVERIFY(contents);
+ QVERIFY(menuBar->count() > 0);
+ QCOMPARE(menuBarPrivate->nativeHandle() != nullptr, native);
+
+ if (menuBarPrivate->nativeHandle()) {
+ // Using native menubar
+ QCOMPARE(contents->height(), window->height());
+ } else {
+ // Not using native menubar
+ QCOMPARE(contents->height(), window->height() - menuBar->height());
+ }
+}
+
+void tst_qquickmenubar::menuPosition()
+{
+ // A Menu.qml will typically have a background with a drop-shadow. And to make
+ // room for this shadow, the Menu itself is made bigger by using Control.insets.
+ // This will make room for both the background and its shadow.
+ // To make sure that the corner of the background (rather than the shadow) ends up
+ // at the requested menu position, the effective position of the menu will be
+ // shifted a bit up and left. This test will therefore check that the corner of the
+ // background ends up that the requested position.
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true);
+ // Use in-scene popups for this test, since we have no guarantee where a window
+ // manager might end up placing a menu.
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("menus.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+
+ QPointF requestedPos{50, 50};
+
+ QQuickMenu *editMenu = menuBar->menuAt(1);
+ QVERIFY(editMenu);
+ editMenu->setX(requestedPos.x());
+ editMenu->setY(requestedPos.y());
+ editMenu->setVisible(true);
+ QTRY_VERIFY(editMenu->isOpened());
+ QCOMPARE(editMenu->x(), requestedPos.x());
+ QCOMPARE(editMenu->y(), requestedPos.y());
+
+ QQuickItem *background = editMenu->background();
+ QVERIFY(background);
+
+ QPointF bgPos = background->mapToItem(editMenu->parentItem(), {0, 0});
+ QCOMPARE(bgPos, requestedPos);
+}
+
+void tst_qquickmenubar::changeDelegate_data()
+{
+ QTest::addColumn<bool>("native");
+ QTest::newRow("not native") << false;
+ if (nativeMenuBarSupported)
+ QTest::newRow("native") << true;
+}
+
+void tst_qquickmenubar::changeDelegate()
+{
+ // Check that you can change the delegate, and that this
+ // will produce new delegate items, except for the MenuBarItem
+ // that is created inline in the QML code, and hence doesn't use the delegate.
+ QFETCH(bool, native);
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, !native);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("nodelegate.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+ QCOMPARE(menuBar->count(), 3);
+
+ QQmlComponent delegate1(&engine);
+ delegate1.setData("import QtQuick.Controls; MenuBarItem {}", QUrl());
+ menuBar->setDelegate(&delegate1);
+
+ auto menuBarItem0_v1 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(0));
+ auto menuBarItem1_v1 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(1));
+ auto menuBarItem2_v1 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(2));
+ QVERIFY(menuBarItem0_v1);
+ QVERIFY(menuBarItem1_v1);
+ QVERIFY(menuBarItem2_v1);
+ QVERIFY(menuBarItem0_v1->isVisible());
+ QVERIFY(menuBarItem1_v1->isVisible());
+ QVERIFY(menuBarItem2_v1->isVisible());
+ QVERIFY(menuBarItem0_v1->menu());
+ QVERIFY(menuBarItem1_v1->menu());
+ QVERIFY(menuBarItem2_v1->menu());
+ QCOMPARE(menuBar->menuAt(0), menuBarItem0_v1->menu());
+ QCOMPARE(menuBar->menuAt(1), menuBarItem1_v1->menu());
+ QCOMPARE(menuBar->menuAt(2), menuBarItem2_v1->menu());
+
+ // Change the delegate
+ QQmlComponent delegate2(&engine);
+ delegate2.setData("import QtQuick.Controls; MenuBarItem {}", QUrl());
+ menuBar->setDelegate(&delegate2);
+
+ auto menuBarItem0_v2 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(0));
+ auto menuBarItem1_v2 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(1));
+ auto menuBarItem2_v2 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(2));
+ QVERIFY(menuBarItem0_v2);
+ QVERIFY(menuBarItem1_v2);
+ QVERIFY(menuBarItem2_v2);
+
+ // The delegate items should now have changed, except for
+ // menuBarItem2, which is not created from the delegate.
+ QVERIFY(menuBarItem0_v2 != menuBarItem0_v1);
+ QVERIFY(menuBarItem1_v2 != menuBarItem1_v1);
+ QCOMPARE(menuBarItem2_v2, menuBarItem2_v1);
+
+ QVERIFY(menuBarItem0_v2->isVisible());
+ QVERIFY(menuBarItem1_v2->isVisible());
+ QVERIFY(menuBarItem2_v2->isVisible());
+ QVERIFY(menuBarItem0_v2->menu());
+ QVERIFY(menuBarItem1_v2->menu());
+ QVERIFY(menuBarItem2_v2->menu());
+ QCOMPARE(menuBar->menuAt(0), menuBarItem0_v2->menu());
+ QCOMPARE(menuBar->menuAt(1), menuBarItem1_v2->menu());
+ QCOMPARE(menuBar->menuAt(2), menuBarItem2_v2->menu());
+}
+
+void tst_qquickmenubar::invalidDelegate_data()
+{
+ QTest::addColumn<bool>("native");
+ QTest::addColumn<bool>("useInvalidDelegate");
+ QTest::newRow("not native, no delegate") << false << false;
+ QTest::newRow("not native, invalid delegate") << false << true;
+ if (nativeMenuBarSupported) {
+ QTest::newRow("native, no delegate") << true << false;
+ QTest::newRow("native, invalid delegate") << true << true;
+ }
+}
+
+void tst_qquickmenubar::invalidDelegate()
+{
+ // Check that QQuickMenuBar can handle a delegate that is either null, or not a
+ // MenuBarItem. The former won't produce any warnings, but the latter should.
+ // In either case, this will not produce visible menus in the menu bar, except
+ // for the menus that are wrapped inside inline MenuBarItems, and therefore
+ // not using the delegate.
+ // To ensure that we still bookkeep the menus for the failing delegates, in case
+ // the delegate changes later, and that functions such as menuAt(index) continues
+ // to work, hidden placeholder MenuBarItems will be used instead.
+ QFETCH(bool, native);
+ QFETCH(bool, useInvalidDelegate);
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, !native);
+ QQmlApplicationEngine engine;
+
+ if (useInvalidDelegate) {
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression("cannot insert menu.*"));
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression("cannot insert menu.*"));
+ }
+
+ if (useInvalidDelegate)
+ engine.load(testFileUrl("invaliddelegate.qml"));
+ else
+ engine.load(testFileUrl("nodelegate.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+ QCOMPARE(menuBar->count(), 3);
+
+ // Menu 2 is an inline MenuBarItem, and is unaffected by the delegate
+ auto inlineMenuBarItem = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(2));
+
+ for (int i = 0; i <= 2; ++i) {
+ auto menuBarItem = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(i));
+ QVERIFY(menuBarItem);
+ auto menu = menuBarItem->menu();
+ QVERIFY(menu);
+ QCOMPARE(menu, menuBar->menuAt(i));
+ if (menuBarItem == inlineMenuBarItem) {
+ QVERIFY(menuBarItem->isVisible());
+ QCOMPARE(bool(QQuickMenuPrivate::get(menu)->maybeNativeHandle()), native);
+ } else {
+ // Menus created from the invalid delegate should be hidden. They should also
+ // not have a native handle, since they should not be in a native menu bar.
+ QVERIFY(!menuBarItem->isVisible());
+ QVERIFY(!bool(QQuickMenuPrivate::get(menu)->maybeNativeHandle()));
+ }
+ }
+
+ // Add a new menu. This one should also be inserted into a placeholder MenuBarItem
+ if (useInvalidDelegate)
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression("cannot insert menu.*"));
+
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick.Controls; Menu { }", QUrl());
+ auto menu = qobject_cast<QQuickMenu *>(component.create());
+ QVERIFY(menu);
+
+ menuBar->addMenu(menu);
+ QCOMPARE(menuBar->count(), 4);
+ auto menuBarItem3 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(3));
+ QVERIFY(menuBarItem3);
+ QVERIFY(!menuBarItem3->isVisible());
+ QCOMPARE(menuBar->menuAt(3), menu);
+ QCOMPARE(menuBar->menuAt(3), menuBarItem3->menu());
+ QVERIFY(!QQuickMenuPrivate::get(menu)->maybeNativeHandle());
+
+ // Finally, set a valid delegate. This will make all MenuBarItems visible.
+ QQmlComponent delegate(&engine);
+ delegate.setData("import QtQuick.Controls; MenuBarItem { }", QUrl());
+ menuBar->setDelegate(&delegate);
+
+ for (int i = 0; i <= 3; ++i) {
+ auto menuBarItem = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(i));
+ QVERIFY(menuBarItem);
+ QVERIFY(menuBarItem->isVisible());
+ auto menu = menuBarItem->menu();
+ QVERIFY(menu);
+ QCOMPARE(menu, menuBar->menuAt(i));
+ QCOMPARE(bool(QQuickMenuPrivate::get(menu)->maybeNativeHandle()), native);
+ }
+
+ // inlineMenuBarItem was not created from a delegate, and shouldn't change
+ QCOMPARE(qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(2)), inlineMenuBarItem);
+}
+
+void tst_qquickmenubar::panMenuBar_data()
+{
+ QTest::addColumn<bool>("usePopupWindow");
+ QTest::newRow("in-scene popup") << false;
+ // Uncomment when popup windows work 100%
+ // if (popupWindowsSupported)
+ // QTest::newRow("popup window") << true;
+}
+
+void tst_qquickmenubar::panMenuBar()
+{
+ // Check that a MenuBarItem's menu opens when you click it. And then check that
+ // if you hover the next MenuBarItem in the MenuBar, that the first one will
+ // close, and the second one will open.
+
+#if !defined(Q_OS_MACOS) || !defined(Q_OS_WINDOWS)
+ QSKIP("This test doesn't pass on e.g QNX. It needs more investigation before it can be enabled");
+#endif
+
+#ifdef Q_OS_ANDROID
+ // Android theme does not use hover effects, so moving the mouse would not
+ // highlight an item
+ QSKIP("Panning of MenuBar not supported");
+#endif
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true);
+ QQmlApplicationEngine engine;
+ engine.load(testFileUrl("menus.qml"));
+
+ QScopedPointer<QQuickApplicationWindow> window(qobject_cast<QQuickApplicationWindow *>(engine.rootObjects().value(0)));
+ QVERIFY(window);
+ QQuickMenuBar *menuBar = window->property("menuBar").value<QQuickMenuBar *>();
+ QVERIFY(menuBar);
+ QQuickMenuBarPrivate *menuBar_d = QQuickMenuBarPrivate::get(menuBar);
+
+ auto menuBarItem0 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(0));
+ auto menuBarItem1 = qobject_cast<QQuickMenuBarItem *>(menuBar->itemAt(1));
+ QVERIFY(menuBarItem0);
+ QVERIFY(menuBarItem1);
+
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, itemSceneCenter(menuBarItem0));
+ QVERIFY(menuBarItem0->isHighlighted());
+ QVERIFY(!menuBarItem1->isHighlighted());
+ QCOMPARE(menuBar_d->currentItem, menuBarItem0);
+ QVERIFY(menuBar_d->currentMenuOpen);
+ QTRY_VERIFY(menuBarItem0->menu()->isOpened());
+
+ QTest::mouseMove(window.data(), itemSceneCenter(menuBarItem1));
+ QVERIFY(!menuBarItem0->isHighlighted());
+ QVERIFY(menuBarItem1->isHighlighted());
+ QCOMPARE(menuBar_d->currentItem, menuBarItem1);
+ QVERIFY(menuBar_d->currentMenuOpen);
+ QTRY_VERIFY(menuBarItem1->menu()->isOpened());
+ QTRY_VERIFY(!menuBarItem0->menu()->isOpened());
+}
+
QTEST_QUICKCONTROLS_MAIN(tst_qquickmenubar)
#include "tst_qquickmenubar.moc"
diff --git a/tests/auto/quickcontrols/qquickpopup/BLACKLIST b/tests/auto/quickcontrols/qquickpopup/BLACKLIST
index bd2185328f..3beb1d6cc7 100644
--- a/tests/auto/quickcontrols/qquickpopup/BLACKLIST
+++ b/tests/auto/quickcontrols/qquickpopup/BLACKLIST
@@ -23,3 +23,7 @@ opensuse-leap
[cursorShape]
opensuse-leap
+
+[popupWindowFocus]
+* # QTBUG-121363
+
diff --git a/tests/auto/quickcontrols/qquickpopup/data/popupCenterIn.qml b/tests/auto/quickcontrols/qquickpopup/data/popupCenterIn.qml
new file mode 100644
index 0000000000..6a67af30fc
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickpopup/data/popupCenterIn.qml
@@ -0,0 +1,22 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+Window {
+ width: 1080
+ height: 720
+
+ property alias popup: simplepopup
+
+ Popup {
+ id: simplepopup
+ anchors.centerIn: parent
+ popupType: Popup.Window
+
+ Text {
+ text: "I am a centered popup"
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickpopup/data/popupWindowFocusHandling.qml b/tests/auto/quickcontrols/qquickpopup/data/popupWindowFocusHandling.qml
new file mode 100644
index 0000000000..1477db047e
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickpopup/data/popupWindowFocusHandling.qml
@@ -0,0 +1,28 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+Window {
+ width: 400
+ height: 400
+
+ property alias popup: simplepopup
+ property alias textField1: outerTextField
+ property alias textField2: innerTextField
+
+ TextField {
+ id: outerTextField
+ focus: true
+ }
+
+ Popup {
+ id: simplepopup
+ popupType: Popup.Window
+ TextField {
+ id: innerTextField
+ focus: true
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickpopup/data/popupWithButtonInBackground.qml b/tests/auto/quickcontrols/qquickpopup/data/popupWithButtonInBackground.qml
new file mode 100644
index 0000000000..b265a80df7
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickpopup/data/popupWithButtonInBackground.qml
@@ -0,0 +1,28 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+Window {
+ width: 1080
+ height: 720
+
+ property alias popup: simplepopup
+
+ Button {
+ text: "Button"
+ }
+
+ Popup {
+ id: simplepopup
+ popupType: Popup.Window
+
+ x: 50
+ y: 50
+
+ Text {
+ text: "I am a very interesting popup"
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickpopup/data/reparentingPopup.qml b/tests/auto/quickcontrols/qquickpopup/data/reparentingPopup.qml
new file mode 100644
index 0000000000..bf622b7713
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickpopup/data/reparentingPopup.qml
@@ -0,0 +1,48 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+Window {
+ width: 400
+ height: 400
+
+ property alias popup: simplepopup
+ property alias rectangle1: item1
+ property alias rectangle2: item2
+ property alias rectangle3: item3
+
+ Popup {
+ id: simplepopup
+ popupType: Popup.Window
+ x: 10
+ y: 10
+ width: 200
+ height: 200
+ }
+
+ Rectangle {
+ id: item1
+ color: "red"
+ width: 200
+ height: 200
+ }
+
+ Rectangle {
+ id: item2
+ color: "green"
+ x: 0
+ y: 200
+ width: parent.width
+ height: 200
+ Rectangle {
+ id: item3
+ color: "blue"
+ x: 200
+ y: 0
+ width: 200
+ height: item2.height
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickpopup/data/simplepopup.qml b/tests/auto/quickcontrols/qquickpopup/data/simplepopup.qml
new file mode 100644
index 0000000000..eeafa10c9e
--- /dev/null
+++ b/tests/auto/quickcontrols/qquickpopup/data/simplepopup.qml
@@ -0,0 +1,22 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+Window {
+ width: 1080
+ height: 720
+
+ property alias popup: simplepopup
+
+ Popup {
+ id: simplepopup
+ x: 50
+ y: 50
+
+ Text {
+ text: "I am a very interesting popup"
+ }
+ }
+}
diff --git a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp
index f894387672..650d168c65 100644
--- a/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp
+++ b/tests/auto/quickcontrols/qquickpopup/tst_qquickpopup.cpp
@@ -16,18 +16,21 @@
#include <QtQuickTestUtils/private/viewtestutils_p.h>
#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
+#include <QtQuickTemplates2/private/qquickbutton_p.h>
#include <QtQuickTemplates2/private/qquickcombobox_p.h>
#include <QtQuickTemplates2/private/qquickdialog_p.h>
+#include <QtQuickTemplates2/private/qquickdrawer_p.h>
#include <QtQuickTemplates2/private/qquickoverlay_p.h>
#include <QtQuickTemplates2/private/qquickoverlay_p_p.h>
#include <QtQuickTemplates2/private/qquickpopup_p.h>
+#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
+#include <QtQuickTemplates2/private/qquickpopupanchors_p.h>
#include <QtQuickTemplates2/private/qquickpopupitem_p_p.h>
-#include <QtQuickTemplates2/private/qquickbutton_p.h>
+#include <QtQuickTemplates2/private/qquickpopupwindow_p_p.h>
#include <QtQuickTemplates2/private/qquickslider_p.h>
#include <QtQuickTemplates2/private/qquickstackview_p.h>
-#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
#include <QtQuickTemplates2/private/qquicktooltip_p.h>
-#include <QtQuickTemplates2/private/qquickdrawer_p.h>
+#include <QtQuick/private/qquicktextinput_p.h>
#include <QtQuick/private/qquicklistview_p.h>
#include <QtQuick/private/qquicktextedit_p.h>
#include <QtQuick/private/qquickdroparea_p.h>
@@ -111,9 +114,21 @@ private slots:
void fadeDimmer();
void noDimmer();
+ void popupWindowPositioning();
+ void popupWindowAnchorsCenterIn_data();
+ void popupWindowAnchorsCenterIn();
+ void popupWindowModality();
+ void popupWindowClosesOnParentWindowClosing();
+ void initialPopupSize_data();
+ void initialPopupSize();
+ void popupWindowChangingParent();
+ void popupWindowFocus();
+ void popupTypeChangeFromWindowToItem();
+ void popupTypeChangeFromItemToWindow();
+
private:
- static bool hasWindowActivation();
QScopedPointer<QPointingDevice> touchScreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
+ bool popupWindowsSupported = false;
};
using namespace Qt::StringLiterals;
@@ -121,11 +136,14 @@ using namespace Qt::StringLiterals;
tst_QQuickPopup::tst_QQuickPopup()
: QQmlDataTest(QT_QMLTEST_DATADIR)
{
+ popupWindowsSupported = QGuiApplicationPrivate::platformIntegration()
+ ->hasCapability(QPlatformIntegration::Capability::MultipleWindows);
}
void tst_QQuickPopup::initTestCase()
{
QQmlDataTest::initTestCase();
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
qputenv("QML_NO_TOUCH_COMPRESSION", "1");
}
@@ -136,11 +154,6 @@ void tst_QQuickPopup::visible_data()
QTest::newRow("ApplicationWindow") << "applicationwindow.qml";
}
-bool tst_QQuickPopup::hasWindowActivation()
-{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
-}
-
void tst_QQuickPopup::visible()
{
QFETCH(QString, source);
@@ -519,8 +532,7 @@ void tst_QQuickPopup::closePolicy_data()
void tst_QQuickPopup::closePolicy()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QFETCH(QString, source);
QFETCH(const QPointingDevice *, device);
@@ -662,8 +674,7 @@ void tst_QQuickPopup::closePolicy_grabberInside()
void tst_QQuickPopup::activeFocusOnClose1()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Test that a popup that never sets focus: true (e.g. ToolTip) doesn't affect
// the active focus item when it closes.
@@ -708,8 +719,7 @@ void tst_QQuickPopup::activeFocusOnClose1()
void tst_QQuickPopup::activeFocusOnClose2()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Test that a popup that sets focus: true but relinquishes focus (e.g. by
// calling forceActiveFocus() on another item) before it closes doesn't
@@ -750,8 +760,7 @@ void tst_QQuickPopup::activeFocusOnClose2()
void tst_QQuickPopup::activeFocusOnClose3()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Test that a closing popup that had focus doesn't steal focus from
// another popup that the focus was transferred to.
@@ -786,8 +795,7 @@ void tst_QQuickPopup::activeFocusOnClose3()
void tst_QQuickPopup::activeFocusOnClosingSeveralPopups()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Test that active focus isn't lost when multiple popup closing simultaneously
QQuickControlsApplicationHelper helper(this, QStringLiteral("activeFocusOnClosingSeveralPopups.qml"));
@@ -838,8 +846,7 @@ void tst_QQuickPopup::activeFocusOnClosingSeveralPopups()
void tst_QQuickPopup::activeFocusAfterExit()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Test that after closing a popup the highest one in z-order receives it instead.
QQuickControlsApplicationHelper helper(this, QStringLiteral("activeFocusAfterExit.qml"));
@@ -890,8 +897,7 @@ void tst_QQuickPopup::activeFocusAfterExit()
void tst_QQuickPopup::activeFocusOnDelayedEnter()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Test that after opening two popups, first of which has an animation, does not cause
// the first one to receive focus after the animation stops.
@@ -919,8 +925,7 @@ void tst_QQuickPopup::activeFocusOnDelayedEnter()
// key events due to having active focus.
void tst_QQuickPopup::activeFocusDespiteLowerStackingOrder()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QStringLiteral("activeFocusOnClose3.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
@@ -961,8 +966,7 @@ void tst_QQuickPopup::activeFocusDespiteLowerStackingOrder()
void tst_QQuickPopup::activeFocusItemAfterWindowInactive()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QStringLiteral("activeFocusAfterWindowInactive.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
@@ -1448,8 +1452,7 @@ void tst_QQuickPopup::componentComplete()
void tst_QQuickPopup::closeOnEscapeWithNestedPopups()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
// Tests the scenario in the Gallery example, where there are nested popups that should
// close in the correct order when the Escape key is pressed.
@@ -1518,8 +1521,7 @@ void tst_QQuickPopup::closeOnEscapeWithNestedPopups()
void tst_QQuickPopup::closeOnEscapeWithVisiblePopup()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, QStringLiteral("closeOnEscapeWithVisiblePopup.qml"));
QVERIFY2(helper.ready, helper.failureMessage());
@@ -1629,8 +1631,7 @@ void tst_QQuickPopup::qquickview()
// QTBUG-73447
void tst_QQuickPopup::disabledPalette()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, "disabledPalette.qml");
QVERIFY2(helper.ready, helper.failureMessage());
@@ -1669,8 +1670,7 @@ void tst_QQuickPopup::disabledPalette()
void tst_QQuickPopup::disabledParentPalette()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, "disabledPalette.qml");
QVERIFY2(helper.ready, helper.failureMessage());
@@ -1778,8 +1778,7 @@ void tst_QQuickPopup::setOverlayParentToNull()
void tst_QQuickPopup::tabFence()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if (QGuiApplication::styleHints()->tabFocusBehavior() != Qt::TabFocusAllControls)
QSKIP("This platform only allows tab focus for text controls");
@@ -1891,8 +1890,7 @@ void tst_QQuickPopup::centerInOverlayWithinStackViewItem()
void tst_QQuickPopup::destroyDuringExitTransition()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
QQuickControlsApplicationHelper helper(this, "destroyDuringExitTransition.qml");
QVERIFY2(helper.ready, helper.failureMessage());
@@ -2387,6 +2385,436 @@ void tst_QQuickPopup::noDimmer()
QTRY_VERIFY(!drawer->isModal());
}
+#define VERIFY_LOCAL_POS(POPUP, EXPECTED) \
+ QTRY_VERIFY2(qAbs(POPUP->x() - qreal(EXPECTED.x())) <= 1, \
+ qPrintable(QStringLiteral("QQuickPopup::x() = %1, expected = %2").arg(POPUP->x()).arg(EXPECTED.x())));\
+ QVERIFY2(qAbs(POPUP->y() - qreal(EXPECTED.y())) <= 1, \
+ qPrintable(QStringLiteral("QQuickPopup::y() = %1, expected = %2").arg(POPUP->y()).arg(EXPECTED.y())))
+
+#define VERIFY_GLOBAL_POS(FROM, POPUPWINDOW, EXPECTED) \
+ QTRY_VERIFY2((POPUPWINDOW->position() - FROM->mapToGlobal(EXPECTED.x(), EXPECTED.y())).manhattanLength() <= 2, \
+ qPrintable(QStringLiteral("PopupWindow pos = (%1, %2), expected (%3, %4)") \
+ .arg(POPUPWINDOW->x()).arg(POPUPWINDOW->y()).arg(EXPECTED.x()).arg(EXPECTED.y())))
+
+void tst_QQuickPopup::popupWindowPositioning()
+{
+ if (!popupWindowsSupported)
+ QSKIP("The platform doesn't support popup windows. Skipping test.");
+
+ QQuickApplicationHelper helper(this, "simplepopup.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *popup = window->contentItem()->findChild<QQuickPopup *>();
+ QVERIFY(popup);
+ auto *popupPrivate = QQuickPopupPrivate::get(popup);
+ QVERIFY(popupPrivate);
+
+ popup->setPopupType(QQuickPopup::Window);
+
+ popup->open();
+ QTRY_VERIFY(popup->isVisible());
+
+ QSignalSpy xSpy(popup, SIGNAL(xChanged()));
+ QSignalSpy ySpy(popup, SIGNAL(yChanged()));
+
+ auto *popupWindow = popupPrivate->popupWindow;
+ QVERIFY(popupWindow);
+
+ // x and y properties should be 50 initially
+ const QPoint initialPos(50, 50);
+
+ VERIFY_GLOBAL_POS(popup->parentItem(), popupWindow, initialPos);
+ VERIFY_LOCAL_POS(popup, initialPos);
+
+ // Move popup via QQuickPopup API
+ const QPoint secondPosition(100, 100);
+ popup->setPosition(secondPosition.toPointF());
+
+ QTRY_COMPARE(xSpy.count(), 1);
+ QCOMPARE(ySpy.count(), 1);
+
+ VERIFY_GLOBAL_POS(popup->parentItem(), popupWindow, secondPosition);
+ VERIFY_LOCAL_POS(popup, secondPosition);
+
+ // Move popup via QWindow API (which uses global coordinates)
+ const QPoint thirdPosition(150, 150);
+ popupWindow->setPosition(popup->parentItem()->mapToGlobal(thirdPosition.x(), thirdPosition.y()).toPoint());
+
+ QTRY_COMPARE(xSpy.count(), 2);
+ QCOMPARE(ySpy.count(), 2);
+
+ VERIFY_GLOBAL_POS(popup->parentItem(), popupWindow, thirdPosition);
+ VERIFY_LOCAL_POS(popup, thirdPosition);
+
+ // Moving parent window should change the popups position (because it's stationary, but x and y are relative coordinates)
+ const QPoint movement(30, 30);
+ const QPoint oldPos = window->position();
+ window->setPosition(oldPos + movement);
+
+ // TODO: Figure out these signals are emitted twice
+ // QTRY_COMPARE(xSpy.count(), 3);
+ // QCOMPARE(ySpy.count(), 3);
+
+ VERIFY_GLOBAL_POS(popup->parentItem(), popupWindow, (thirdPosition - movement));
+}
+
+void tst_QQuickPopup::popupWindowAnchorsCenterIn_data()
+{
+ QTest::addColumn<bool>("centerInParent");
+ QTest::newRow("parent") << true;
+ QTest::newRow("overlay") << false;
+}
+
+void tst_QQuickPopup::popupWindowAnchorsCenterIn()
+{
+ QFETCH(bool, centerInParent);
+
+ if (!popupWindowsSupported)
+ QSKIP("The platform doesn't support popup windows. Skipping test.");
+
+ QQuickApplicationHelper helper(this, "popupCenterIn.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *popup = window->contentItem()->findChild<QQuickPopup *>();
+ QVERIFY(popup);
+ auto *popupPrivate = QQuickPopupPrivate::get(popup);
+ QVERIFY(popupPrivate);
+
+ popupPrivate->getAnchors()->setCenterIn(centerInParent ? window->contentItem() : QQuickOverlay::overlay(window));
+
+ popup->open();
+ QTRY_VERIFY(popup->isVisible());
+
+ auto *popupWindow = popupPrivate->popupWindow;
+ QVERIFY(popupWindow);
+
+ const QPoint centeredPosition(qFloor(window->width() / 2 - popupWindow->width() / 2), qFloor(window->height() / 2 - popupWindow->height() / 2));
+
+ VERIFY_GLOBAL_POS(popup->parentItem(), popupWindow, centeredPosition);
+ VERIFY_LOCAL_POS(popup, centeredPosition);
+}
+
+void tst_QQuickPopup::popupWindowModality()
+{
+ QSKIP("The behavior isn't correctly implemented yet. Waiting for patch in qtbase");
+
+ if (!popupWindowsSupported)
+ QSKIP("The platform doesn't support popup windows. Skipping test.");
+
+ QQuickApplicationHelper helper(this, "popupWithButtonInBackground.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *popup = window->contentItem()->findChild<QQuickPopup *>();
+ QVERIFY(popup);
+
+ auto *popupPrivate = QQuickPopupPrivate::get(popup);
+ QVERIFY(popupPrivate);
+
+ auto *button = window->findChild<QQuickButton *>();
+ QVERIFY(button);
+
+ QSignalSpy buttonSpy(button, SIGNAL(clicked()));
+
+ popup->open();
+ QTRY_VERIFY(popup->isVisible());
+
+ auto *popupWindow = popupPrivate->popupWindow;
+ QVERIFY(popupWindow);
+ QVERIFY(popupWindow->isVisible());
+ // NonModal by default
+ QCOMPARE(popupWindow->modality(), Qt::NonModal);
+
+ // Non modal popups should close on press outside
+ QTest::mouseClick(helper.window, Qt::LeftButton, Qt::NoModifier, button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint());
+ QTRY_COMPARE(buttonSpy.count(), 1);
+ QVERIFY(!popupWindow->isVisible());
+
+ popup->setModal(true);
+ popup->open();
+ QTRY_VERIFY(popup->isVisible());
+ QVERIFY(popupWindow->isVisible());
+ QCOMPARE(popupWindow->modality(), Qt::ApplicationModal);
+
+ // Pressing outside the popup shouldn't cause the button to get the event, because of modality.
+ QTest::mouseClick(helper.window, Qt::LeftButton, Qt::NoModifier, button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint());
+ QCoreApplication::processEvents();
+ QCOMPARE(buttonSpy.count(), 1);
+ QVERIFY(popupWindow->isVisible());
+
+ popup->close();
+ QTRY_VERIFY(!popup->isVisible());
+}
+
+void tst_QQuickPopup::popupWindowClosesOnParentWindowClosing()
+{
+ QSKIP("The behavior isn't correctly implemented yet. Waiting for patch in qtbase");
+ if (!popupWindowsSupported)
+ QSKIP("The platform doesn't support popup windows. Skipping test.");
+
+ QQuickApplicationHelper helper(this, "simplepopup.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *popup = window->contentItem()->findChild<QQuickPopup *>();
+ QVERIFY(popup);
+ auto *popupPrivate = QQuickPopupPrivate::get(popup);
+ QVERIFY(popupPrivate);
+
+ popup->setPopupType(QQuickPopup::Window);
+
+ popup->open();
+ QTRY_VERIFY(popup->isVisible());
+
+ auto *popupWindow = popupPrivate->popupWindow;
+ QVERIFY(popupWindow);
+ QVERIFY(popupWindow->isVisible());
+
+ // Closing parent window, should close child window;
+ window->close();
+
+ QTRY_VERIFY(!window->isVisible());
+ QTRY_VERIFY(!popupWindow->isVisible());
+}
+
+void tst_QQuickPopup::initialPopupSize_data()
+{
+ QTest::addColumn<QQuickPopup::PopupType>("popupType");
+
+ QTest::newRow("Item") << QQuickPopup::Item;
+ if (popupWindowsSupported)
+ QTest::newRow("Window") << QQuickPopup::Window;
+}
+
+void tst_QQuickPopup::initialPopupSize()
+{
+ QFETCH(QQuickPopup::PopupType, popupType);
+ QQuickApplicationHelper helper(this, "reparentingPopup.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *popup = window->contentItem()->findChild<QQuickPopup *>();
+ QVERIFY(popup);
+ auto *popupPrivate = QQuickPopupPrivate::get(popup);
+ QVERIFY(popupPrivate);
+
+ popup->setPopupType(popupType);
+ popup->open();
+ QTRY_VERIFY(popup->isOpened());
+
+ QCOMPARE(popup->width(), 200);
+ QCOMPARE(popup->height(), 200);
+
+ auto popupItem = popupPrivate->popupItem;
+ QCOMPARE(popupItem->width(), 200);
+ QCOMPARE(popupItem->height(), 200);
+
+ if (popupType == QQuickPopup::Window) {
+ auto *popupWindow = popupPrivate->popupWindow;
+ QVERIFY(popupWindow);
+ QVERIFY(popupWindow->isVisible());
+ QCOMPARE(popupWindow->width(), 200);
+ QCOMPARE(popupWindow->height(), 200);
+ }
+}
+
+void tst_QQuickPopup::popupWindowChangingParent()
+{
+ if (!popupWindowsSupported)
+ QSKIP("The platform doesn't support popup windows. Skipping test.");
+
+ QQuickApplicationHelper helper(this, "reparentingPopup.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickWindow *window = helper.window;
+ auto *popup = window->contentItem()->findChild<QQuickPopup *>();
+ QVERIFY(popup);
+ auto *popupPrivate = QQuickPopupPrivate::get(popup);
+ QVERIFY(popupPrivate);
+
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ QVERIFY(!popup->isVisible());
+
+ QQuickItem *item1 = window->property("rectangle1").value<QQuickItem *>();
+ QVERIFY(item1);
+
+ QQuickItem *item2 = window->property("rectangle2").value<QQuickItem *>();
+ QVERIFY(item2);
+
+ QQuickItem *item3 = window->property("rectangle3").value<QQuickItem *>();
+ QVERIFY(item3);
+
+ popup->open();
+ QTRY_VERIFY(popup->isOpened());
+
+ QTRY_VERIFY(popupPrivate->popupWindow);
+ QWindow *popupWindow = popupPrivate->popupWindow;
+
+ QTRY_VERIFY(popupWindow->isVisible());
+ QVERIFY(QTest::qWaitForWindowExposed(popupWindow));
+
+ const QPoint initialPos(10, 10);
+
+ VERIFY_GLOBAL_POS(item1, popupWindow, initialPos);
+ VERIFY_LOCAL_POS(popup, initialPos);
+
+ popup->setParentItem(item1);
+
+ VERIFY_GLOBAL_POS(item1, popupWindow, initialPos);
+ VERIFY_LOCAL_POS(popup, initialPos);
+
+ popup->setParentItem(item2);
+
+ VERIFY_GLOBAL_POS(item2, popupWindow, initialPos);
+ VERIFY_LOCAL_POS(popup, initialPos);
+
+ popup->setParentItem(item3);
+
+ VERIFY_GLOBAL_POS(item3, popupWindow, initialPos);
+ VERIFY_LOCAL_POS(popup, initialPos);
+}
+
+void tst_QQuickPopup::popupWindowFocus()
+{
+ if (!popupWindowsSupported)
+ QSKIP("The platform doesn't support popup windows. Skipping test.");
+
+ QQuickApplicationHelper helper(this, "popupWindowFocusHandling.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickWindow *window = helper.window;
+ QVERIFY(window);
+ auto *popup = window->contentItem()->findChild<QQuickPopup *>();
+ QVERIFY(popup);
+ auto *popupPrivate = QQuickPopupPrivate::get(popup);
+ QVERIFY(popupPrivate);
+ QQuickTextInput *textField1 = window->property("textField1").value<QQuickTextInput *>();
+ QVERIFY(textField1);
+ QQuickTextInput *textField2 = window->property("textField2").value<QQuickTextInput *>();
+ QVERIFY(textField2);
+
+ window->show();
+ QVERIFY(QTest::qWaitForWindowFocused(window));
+ QVERIFY(QGuiApplication::focusObject() == textField1);
+ QTest::keyClick(helper.window, Qt::Key_Q);
+ QTRY_COMPARE(textField1->text(), "q");
+ popup->open();
+ QTRY_VERIFY(popup->isVisible());
+ auto *popupWindow = popupPrivate->popupWindow;
+ QVERIFY(popupWindow);
+ QVERIFY(popupWindow->isVisible());
+ // The focusWindow should still be the main window,
+ // the popup window should get its event forwarded via the delivery agent
+ QVERIFY(QGuiApplication::focusWindow() == helper.window);
+ QVERIFY(popupWindow->focusObject() == textField2);
+ QTest::keyClick(popupWindow, Qt::Key_T);
+ QTRY_COMPARE(textField2->text(), "t");
+ popup->close();
+ QTRY_VERIFY(!popup->isVisible());
+ QVERIFY(QGuiApplication::focusObject() == textField1);
+}
+
+void tst_QQuickPopup::popupTypeChangeFromWindowToItem()
+{
+ if (!popupWindowsSupported)
+ QSKIP("The platform doesn't support native popup windows. Skipping test.");
+
+ QQuickApplicationHelper helper(this, "simplepopup.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ auto *popup = window->contentItem()->findChild<QQuickPopup *>();
+ QVERIFY(popup);
+ auto *popupPrivate = QQuickPopupPrivate::get(popup);
+ QVERIFY(popupPrivate);
+
+ QQuickOverlay *overlay = QQuickOverlay::overlay(window);
+ QVERIFY(overlay);
+
+ popup->setPopupType(QQuickPopup::Window);
+
+ popup->open();
+ QTRY_VERIFY(popup->isOpened());
+ const QWindow *popupWindow = popupPrivate->popupWindow;
+ QVERIFY(popupWindow);
+ QTRY_VERIFY(popupWindow->isVisible());
+ QCOMPARE(popupPrivate->popupItem->position(), QPointF(0, 0));
+ QVERIFY(!overlay->childItems().contains(popup->popupItem()));
+
+ popup->close();
+ QTRY_VERIFY(!popup->isVisible());
+ QVERIFY(!popupWindow->isVisible());
+
+ popup->setPopupType(QQuickPopup::Item);
+
+ popup->open();
+ QTRY_VERIFY(popup->isOpened());
+ QVERIFY(!popupWindow || !popupWindow->isVisible());
+ QCOMPARE(popupPrivate->popupItem->position(), QPointF(50, 50));
+ QVERIFY(overlay->childItems().contains(popup->popupItem()));
+
+ popup->close();
+}
+
+void tst_QQuickPopup::popupTypeChangeFromItemToWindow()
+{
+ if (!popupWindowsSupported)
+ QSKIP("The platform doesn't support popup windows. Skipping test.");
+
+ QQuickApplicationHelper helper(this, "simplepopup.qml");
+ QVERIFY2(helper.ready, helper.failureMessage());
+ QQuickWindow *window = helper.window;
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ auto *popup = window->contentItem()->findChild<QQuickPopup *>();
+ QVERIFY(popup);
+ auto *popupPrivate = QQuickPopupPrivate::get(popup);
+ QVERIFY(popupPrivate);
+
+ QQuickOverlay *overlay = QQuickOverlay::overlay(window);
+ QVERIFY(overlay);
+
+ popup->setPopupType(QQuickPopup::Item);
+
+ popup->open();
+ QTRY_VERIFY(popup->isOpened());
+ QVERIFY(!popupPrivate->popupWindow);
+ QCOMPARE(popupPrivate->popupItem->position(), QPointF(50, 50));
+ QVERIFY(overlay->childItems().contains(popup->popupItem()));
+
+ popup->close();
+ QTRY_VERIFY(!popup->isVisible());
+
+ popup->setPopupType(QQuickPopup::Window);
+
+ popup->open();
+ QTRY_VERIFY(popup->isOpened());
+ const QWindow *popupWindow = popupPrivate->popupWindow;
+ QVERIFY(popupWindow);
+ QTRY_VERIFY(popupWindow->isVisible());
+ QCOMPARE(popupPrivate->popupItem->position(), QPointF(0, 0));
+ QVERIFY(!overlay->childItems().contains(popup->popupItem()));
+
+ popup->close();
+}
+
QTEST_QUICKCONTROLS_MAIN(tst_QQuickPopup)
#include "tst_qquickpopup.moc"
diff --git a/tests/auto/quickcontrols/qquicktextarea/tst_qquicktextarea.cpp b/tests/auto/quickcontrols/qquicktextarea/tst_qquicktextarea.cpp
index a576bb7941..75e2550d7a 100644
--- a/tests/auto/quickcontrols/qquicktextarea/tst_qquicktextarea.cpp
+++ b/tests/auto/quickcontrols/qquicktextarea/tst_qquicktextarea.cpp
@@ -12,6 +12,7 @@
#include <QtQuick/qquickview.h>
#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <QtQuickTemplates2/private/qquicktextarea_p.h>
#include <QtQuickControlsTestUtils/private/qtest_quickcontrols_p.h>
@@ -29,7 +30,6 @@ private slots:
void touchscreenSetsFocusAndMovesCursor();
private:
- static bool hasWindowActivation();
QScopedPointer<QPointingDevice> touchDevice = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
};
@@ -102,8 +102,7 @@ void tst_QQuickTextArea::touchscreenDoesNotSelect()
void tst_QQuickTextArea::touchscreenSetsFocusAndMovesCursor()
{
- if (!hasWindowActivation())
- QSKIP("Window activation is not supported");
+ SKIP_IF_NO_WINDOW_ACTIVATION
qunsetenv("QT_QUICK_CONTROLS_TEXT_SELECTION_BEHAVIOR");
QQuickView window;
@@ -158,11 +157,6 @@ void tst_QQuickTextArea::touchscreenSetsFocusAndMovesCursor()
QCOMPARE_GT(top->selectedText().size(), 0);
}
-bool tst_QQuickTextArea::hasWindowActivation()
-{
- return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
-}
-
QTEST_QUICKCONTROLS_MAIN(tst_QQuickTextArea)
#include "tst_qquicktextarea.moc"
diff --git a/tests/auto/quickcontrols/qquickuniversalstyle/tst_qquickuniversalstyle.cpp b/tests/auto/quickcontrols/qquickuniversalstyle/tst_qquickuniversalstyle.cpp
index f703c549f8..538bac0203 100644
--- a/tests/auto/quickcontrols/qquickuniversalstyle/tst_qquickuniversalstyle.cpp
+++ b/tests/auto/quickcontrols/qquickuniversalstyle/tst_qquickuniversalstyle.cpp
@@ -2,4 +2,18 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtQuickTest/quicktest.h>
-QUICK_TEST_MAIN(tst_qquickuniversalstyle)
+
+class Setup : public QObject
+{
+ Q_OBJECT
+
+public slots:
+ void applicationAvailable()
+ {
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
+ }
+};
+
+QUICK_TEST_MAIN_WITH_SETUP(tst_qquickuniversalstyle, Setup)
+
+#include "tst_qquickuniversalstyle.moc"
diff --git a/tests/auto/quickcontrols/snippets/tst_snippets.cpp b/tests/auto/quickcontrols/snippets/tst_snippets.cpp
index f0d1da48d7..68e6ef5dfa 100644
--- a/tests/auto/quickcontrols/snippets/tst_snippets.cpp
+++ b/tests/auto/quickcontrols/snippets/tst_snippets.cpp
@@ -39,6 +39,9 @@ static QMap<QString, QStringPair> findSnippets(const QDir &inputDir, const QDir
void tst_Snippets::initTestCase()
{
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuWindows);
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
+
qInfo() << "Snippets are taken from" << QQC2_SNIPPETS_PATH;
QDir snippetsDir(QQC2_SNIPPETS_PATH);
diff --git a/tests/auto/quickdialogs/qquickfolderdialogimpl/tst_qquickfolderdialogimpl.cpp b/tests/auto/quickdialogs/qquickfolderdialogimpl/tst_qquickfolderdialogimpl.cpp
index 2afcd81a44..f4e35a37bf 100644
--- a/tests/auto/quickdialogs/qquickfolderdialogimpl/tst_qquickfolderdialogimpl.cpp
+++ b/tests/auto/quickdialogs/qquickfolderdialogimpl/tst_qquickfolderdialogimpl.cpp
@@ -814,7 +814,6 @@ void tst_QQuickFolderDialogImpl::itemsDisabledWhenNecessary()
QVERIFY(breadcrumbBar->textField()->isVisible());
QCOMPARE(openButton->isEnabled(), false);
#endif
-
// Hide it with the escape key. The Open button should now be enabled.
QTest::keyClick(dialogHelper.window(), Qt::Key_Escape);
QVERIFY(!breadcrumbBar->textField()->isVisible());
diff --git a/tests/auto/quickdialogs/qquickfontdialogimpl/BLACKLIST b/tests/auto/quickdialogs/qquickfontdialogimpl/BLACKLIST
index 7d88c9868a..39d2a543c0 100644
--- a/tests/auto/quickdialogs/qquickfontdialogimpl/BLACKLIST
+++ b/tests/auto/quickdialogs/qquickfontdialogimpl/BLACKLIST
@@ -2,3 +2,4 @@
# QTBUG-94225
[clickAroundInTheFamilyListView]
b2qt
+
diff --git a/tests/auto/quickdialogs/qquickfontdialogimpl/tst_qquickfontdialogimpl.cpp b/tests/auto/quickdialogs/qquickfontdialogimpl/tst_qquickfontdialogimpl.cpp
index dc0d547fe9..90bc3503b9 100644
--- a/tests/auto/quickdialogs/qquickfontdialogimpl/tst_qquickfontdialogimpl.cpp
+++ b/tests/auto/quickdialogs/qquickfontdialogimpl/tst_qquickfontdialogimpl.cpp
@@ -273,6 +273,8 @@ void tst_QQuickFontDialogImpl::settingUnderlineAndStrikeoutEffects()
QVERIFY(dialogHelper.dialog->selectedFont().underline());
QVERIFY(!dialogHelper.dialog->selectedFont().strikeOut());
+ QVERIFY(QQuickTest::qWaitForPolish(dialogHelper.window()));
+
QVERIFY(clickButton(underlineCheckBox));
QCOMPARE(selectedFontSpy.size(), 2);
diff --git a/tests/auto/quickwidgets/qquickwidget/BLACKLIST b/tests/auto/quickwidgets/qquickwidget/BLACKLIST
index 095e9ee484..8b5585a41e 100644
--- a/tests/auto/quickwidgets/qquickwidget/BLACKLIST
+++ b/tests/auto/quickwidgets/qquickwidget/BLACKLIST
@@ -1,5 +1,12 @@
[tabKey]
opensuse-42.3
opensuse-leap
+macos-12
[enterLeave]
macos
+[focusOnClickInProxyWidget]
+macos-12
+[focusPreserved]
+macos-12
+[synthMouseFromTouch]
+macos-12
diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
index 0067c716e0..8e8e452120 100644
--- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
+++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp
@@ -14,6 +14,7 @@
#include <QtQuick/private/qquicktaphandler_p.h>
#include <QtQuickTemplates2/private/qquickbutton_p.h>
#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <QtGui/QWindow>
#include <QtGui/QScreen>
#include <QtGui/QImage>
@@ -142,6 +143,7 @@ private slots:
void focusPreserved();
void accessibilityHandlesViewChange();
void cleanupRhi();
+ void dontRecreateRootElementOnWindowChange();
private:
QPointingDevice *device = QTest::createTouchDevice();
@@ -991,8 +993,7 @@ void tst_qquickwidget::focusOnClickInProxyWidget()
void tst_qquickwidget::focusPreserved()
{
- if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
- QSKIP("Window Activation is not supported.");
+ SKIP_IF_NO_WINDOW_ACTIVATION
if (QGuiApplication::platformName() == "android")
QSKIP("Test doesn't exit cleanly on Android and generates many warnings - QTBUG-112696");
@@ -1093,6 +1094,21 @@ void tst_qquickwidget::cleanupRhi()
topLevel.create();
}
+void tst_qquickwidget::dontRecreateRootElementOnWindowChange()
+{
+ auto *quickWidget = new QQuickWidget();
+ quickWidget->setSource(testFileUrl("rectangle.qml"));
+ QObject *item = quickWidget->rootObject();
+
+ bool wasDestroyed = false;
+ QObject::connect(item, &QObject::destroyed, this, [&] { wasDestroyed = true; });
+
+ QEvent event(QEvent::WindowChangeInternal);
+ QCoreApplication::sendEvent(quickWidget, &event);
+
+ QVERIFY(!wasDestroyed);
+}
+
QTEST_MAIN(tst_qquickwidget)
#include "tst_qquickwidget.moc"
diff --git a/tests/baseline/scenegraph/data/shape/shape_fillItem.qml b/tests/baseline/scenegraph/data/shape/shape_fillItem.qml
new file mode 100644
index 0000000000..0862e364b5
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shape/shape_fillItem.qml
@@ -0,0 +1,177 @@
+import QtQuick
+import QtQuick.Shapes
+
+Item {
+ width: 640
+ height: 840
+
+ ListModel {
+ id: renderers
+ ListElement { renderer: Shape.GeometryRenderer; rotationAmount: 0 }
+ ListElement { renderer: Shape.GeometryRenderer; rotationAmount: 30 }
+ ListElement { renderer: Shape.CurveRenderer; rotationAmount: 0 }
+ ListElement { renderer: Shape.CurveRenderer; rotationAmount: 30 }
+ }
+
+ Image {
+ id: image
+ visible: false
+ source: "../shared/col320x480.jpg"
+ }
+
+ Image {
+ id: tiledImage
+ visible: false
+ source: "../shared/col320x480.jpg"
+ layer.enabled: true
+ layer.smooth: true
+ layer.wrapMode: ShaderEffectSource.Repeat
+ }
+
+ Image {
+ id: asynchronousImage
+ visible: false
+ source: "../shared/col320x480.jpg"
+ layer.enabled: true
+ layer.smooth: true
+ layer.wrapMode: ShaderEffectSource.Repeat
+ asynchronous: true
+ }
+
+ Rectangle {
+ id: item
+ visible: false
+ layer.enabled: true
+ layer.smooth: true
+ layer.wrapMode: ShaderEffectSource.Repeat
+ color: "cyan"
+ width: 20
+ height: 20
+ Text {
+ anchors.centerIn: parent
+ text: "😊"
+ }
+ }
+
+ Rectangle {
+ id: sourceItem
+ color: "cyan"
+ width: 20
+ height: 20
+ Text {
+ anchors.centerIn: parent
+ text: "😁"
+ }
+ }
+
+ ShaderEffectSource {
+ id: shaderEffectSource
+ sourceItem: sourceItem
+ width: 20
+ height: 20
+ wrapMode: ShaderEffectSource.Repeat
+ visible: false
+ hideSource: true
+ smooth: true
+ }
+
+ Row {
+ anchors.fill: parent
+ Repeater {
+ model: renderers
+ Column {
+ Shape {
+ id: shape
+ preferredRendererType: renderer
+ width: 160
+ height: 700
+ property real rotate: rotationAmount
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillItem: image
+ fillTransform: PlanarTransform.fromRotate(shape.rotate)
+
+ PathRectangle {
+ x: 10; y: 10
+ width: 140
+ height: 100
+ }
+
+ // startX: 10; startY: 10
+ // PathLine { relativeX: 140; relativeY: 0 }
+ // PathLine { relativeX: 0; relativeY: 100 }
+ // PathLine { relativeX: -140; relativeY: 0 }
+ // PathLine { relativeX: 0; relativeY: -100 }
+ }
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillItem: tiledImage
+
+ PathRectangle {
+ x: 10; y: 10 + 1 * 140
+ width: 140
+ height: 100
+ }
+ fillTransform: PlanarTransform.fromRotate(shape.rotate)
+ }
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillItem: item
+ fillTransform: PlanarTransform.fromRotate(shape.rotate)
+
+ PathRectangle {
+ x: 10; y: 10 + 2 * 140
+ width: 140
+ height: 100
+ }
+ }
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillItem: asynchronousImage
+ fillTransform: PlanarTransform.fromRotate(shape.rotate)
+
+ PathRectangle {
+ x: 10; y: 10 + 3 * 140
+ width: 140
+ height: 100
+ }
+ }
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillItem: shaderEffectSource
+ fillTransform: PlanarTransform.fromRotate(shape.rotate)
+
+ PathRectangle {
+ x: 10; y: 10 + 4 * 140
+ width: 140
+ height: 100
+ }
+ }
+ }
+
+ Shape {
+ preferredRendererType: renderer
+ width: 160
+ height: 200
+ x: 10
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillItem: image
+ fillTransform: PlanarTransform.fromRotate(shape.rotate)
+
+ PathRectangle {
+ width: 140
+ height: 100
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/shape/shape_gradient_xf.qml b/tests/baseline/scenegraph/data/shape/shape_gradient_xf.qml
new file mode 100644
index 0000000000..a0a33d9f2c
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shape/shape_gradient_xf.qml
@@ -0,0 +1,81 @@
+import QtQuick
+import QtQuick.Shapes
+
+Item {
+ width: 320
+ height: 480
+
+ ListModel {
+ id: renderers
+ ListElement { renderer: Shape.GeometryRenderer }
+ ListElement { renderer: Shape.CurveRenderer }
+ }
+
+ Row {
+ Repeater {
+ model: renderers
+ Column {
+ Shape {
+ preferredRendererType: renderer
+ width: 160
+ height: 150
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillGradient: LinearGradient {
+ y1: 50; y2: 80
+ GradientStop { position: 0; color: "black" }
+ GradientStop { position: 1; color: "cyan" }
+ }
+ fillTransform: PlanarTransform.fromAffineMatrix(0.8, 0.2, 0.3, 1.5, 20, -50 + startY)
+
+ startX: 10; startY: 10
+ PathLine { relativeX: 140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: 100 }
+ PathLine { relativeX: -140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: -100 }
+ }
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillGradient: RadialGradient {
+ centerX: 80
+ centerY: 75
+ centerRadius: centerY
+ focalX: centerX
+ focalY: centerY
+ GradientStop { position: 0; color: "black" }
+ GradientStop { position: .5; color: "cyan" }
+ GradientStop { position: 1; color: "black" }
+ }
+ fillTransform: PlanarTransform.fromAffineMatrix(0.8, 0.2, 0.3, 1.5, 20, -50 + startY)
+
+ startX: 10; startY: 10 + 1 * 140
+ PathLine { relativeX: 140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: 100 }
+ PathLine { relativeX: -140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: -100 }
+ }
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillGradient: ConicalGradient {
+ centerX: 80
+ centerY: 75
+ GradientStop { position: 0; color: "black" }
+ GradientStop { position: .5; color: "cyan" }
+ GradientStop { position: 1; color: "black" }
+ }
+ fillTransform: PlanarTransform.fromAffineMatrix(0.8, 0.2, 0.3, 1.5, 20, -50 + startY)
+
+ startX: 10; startY: 10 + 2 * 140
+ PathLine { relativeX: 140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: 100 }
+ PathLine { relativeX: -140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: -100 }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/shape/shape_intersecting8.qml b/tests/baseline/scenegraph/data/shape/shape_intersecting8.qml
new file mode 100644
index 0000000000..fa6e062e17
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shape/shape_intersecting8.qml
@@ -0,0 +1,64 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Shapes
+
+Item {
+ width: 600
+ height: 600
+
+ ListModel {
+ id: fillRules
+ ListElement { fillrule: ShapePath.WindingFill }
+ ListElement { fillrule: ShapePath.OddEvenFill }
+ }
+
+ ListModel {
+ id: renderers
+ ListElement { renderer: Shape.GeometryRenderer }
+ ListElement { renderer: Shape.CurveRenderer }
+ }
+
+ ListModel {
+ id: svgstrings
+ ListElement { scaleToFit: 0.6; offsetX: 20; offsetY: 20; pathString: "M 10 100 Q 10 89.6447 17.3223 82.3223 Q 24.6447 75 35 75 Q 45.3553 75 52.6777 82.3223 Q 60 89.6447 60 100 Q 60 85.5025 67.3223 75.2513 Q 74.6447 65 85 65 Q 95.3553 65 102.678 75.2513 Q 110 85.5025 110 100 Q 110 75.1472 117.322 57.5736 Q 124.645 40 135 40 Q 145.355 40 152.678 57.5736 Q 160 75.1472 160 100 Q 171.603 83.923 185 83.923 Q 198.397 83.923 210 100 L 10 100" }
+ }
+ Column {
+ Repeater {
+ model: renderers
+ Column {
+ Repeater {
+ model: fillRules
+ Row {
+ Repeater {
+ model: svgstrings
+ Rectangle {
+ width: 150
+ height: 150
+ border.color: "black"
+
+ Shape {
+ preferredRendererType: renderer
+ ShapePath {
+ fillColor: renderer == Shape.CurveRenderer ? "#99483d8b" : "#99dc143c"
+ fillRule: fillrule
+ strokeWidth: 0
+ PathSvg { path: pathString }
+ }
+
+ transform: Matrix4x4 {
+ matrix: Qt.matrix4x4(scaleToFit, 0, 0, offsetX,
+ 0, scaleToFit, 0, offsetY,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/shape/shape_rectangle.qml b/tests/baseline/scenegraph/data/shape/shape_rectangle.qml
new file mode 100644
index 0000000000..50e2895f85
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shape/shape_rectangle.qml
@@ -0,0 +1,151 @@
+import QtQuick
+import QtQuick.Shapes
+
+Rectangle {
+ width: 320
+ height: 480
+ color: "lightgray"
+
+ ListModel {
+ id: renderers
+ ListElement { renderer: Shape.GeometryRenderer }
+ ListElement { renderer: Shape.CurveRenderer }
+ }
+
+ Row {
+ padding: 10
+ Repeater {
+ model: renderers
+ Column {
+ spacing: 10
+ Shape {
+ width: 160
+ preferredRendererType: renderer
+
+ ShapePath {
+ fillColor: "transparent"
+ strokeColor: "blue"
+ strokeWidth: 1
+
+ PathRectangle {
+ x: 20; y: 0
+ width: 100; height: 20
+ }
+
+ PathRectangle {
+ x: 20.5; y: 30.5
+ width: 100; height: 20
+ }
+ }
+ }
+
+ Shape {
+ width: 160
+ preferredRendererType: renderer
+
+ ShapePath {
+ fillColor: "yellow"
+ strokeColor: "transparent"
+
+ PathRectangle {
+ x: 20; y: 0
+ width: 100; height: 20
+ }
+
+ PathRectangle {
+ x: 20.5; y: 30.5
+ width: 100; height: 20
+ }
+ }
+ }
+
+ Shape {
+ width: 160
+ preferredRendererType: renderer
+
+ ShapePath {
+ fillColor: "yellow"
+ strokeColor: "green"
+ strokeWidth: 5
+ joinStyle: ShapePath.RoundJoin
+
+ PathRectangle {
+ x: 20; y: 00
+ width: 100; height: 20
+ }
+
+ PathRectangle {
+ x: 20; y: 30
+ width: 100; height: 20
+ radius: 5
+ }
+ }
+
+ ShapePath {
+ fillColor: "yellow"
+ strokeColor: "green"
+ strokeWidth: 5
+ joinStyle: ShapePath.MiterJoin
+
+ PathRectangle {
+ x: 20; y: 60
+ width: 100; height: 20
+ }
+
+ PathRectangle {
+ x: 20; y: 90
+ width: 100; height: 20
+ radius: 5
+ }
+
+ PathRectangle {
+ x: 20; y: 120
+ width: 100; height: 20
+ radius: 50
+ }
+
+ PathRectangle {
+ x: 20; y: 150
+ width: 100; height: 30
+ radius: 10
+ topLeftRadius: 50
+ bottomRightRadius: 5
+ bottomLeftRadius: 0
+ }
+ }
+ }
+
+ Rectangle {
+ id: rect
+ width: 120
+ height: 60
+ color: "white"
+ border.width: 20
+ border.color: "blue"
+ topRightRadius: 30
+ }
+
+ Shape {
+ width: 160
+ preferredRendererType: renderer
+
+ ShapePath {
+ id: myPath
+ fillColor: rect.color
+ strokeColor: rect.border.color
+ strokeWidth: rect.border.width
+ joinStyle: ShapePath.MiterJoin
+
+ PathRectangle {
+ width: rect.width
+ height: rect.height
+ topRightRadius: rect.topRightRadius
+ strokeAdjustment: myPath.strokeWidth
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/tests/baseline/scenegraph/data/shape/shape_spread_xf.qml b/tests/baseline/scenegraph/data/shape/shape_spread_xf.qml
new file mode 100644
index 0000000000..c9f67e472d
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shape/shape_spread_xf.qml
@@ -0,0 +1,47 @@
+import QtQuick
+import QtQuick.Shapes
+
+Item {
+ width: 320
+ height: 480
+
+ ListModel {
+ id: renderers
+ ListElement { renderer: Shape.GeometryRenderer }
+ ListElement { renderer: Shape.CurveRenderer }
+ }
+
+ Row {
+ Repeater {
+ model: renderers
+ Column {
+ Repeater {
+ model: 3
+ Shape {
+ preferredRendererType: renderer
+ width: 160
+ height: 150
+ ShapePath {
+ strokeColor: "transparent"
+
+ fillGradient: LinearGradient {
+ id: grad
+ y1: 50; y2: 80
+ spread: model.index === 0 ? ShapeGradient.PadSpread : (model.index === 1 ? ShapeGradient.RepeatSpread : ShapeGradient.ReflectSpread)
+ GradientStop { position: 0; color: "black" }
+ GradientStop { position: 1; color: "red" }
+ }
+ fillTransform: PlanarTransform.fromShear(0, 0.2)
+
+ startX: 10; startY: 10
+ PathLine { relativeX: 140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: 100 }
+ PathLine { relativeX: -140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: -100 }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/shape/shape_updatecolor.qml b/tests/baseline/scenegraph/data/shape/shape_updatecolor.qml
new file mode 100644
index 0000000000..32cc73ad45
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shape/shape_updatecolor.qml
@@ -0,0 +1,77 @@
+import QtQuick
+import QtQuick.Shapes
+
+Item {
+ width: 320
+ height: 800
+
+ ListModel {
+ id: renderers
+ ListElement { renderer: Shape.GeometryRenderer }
+ ListElement { renderer: Shape.CurveRenderer }
+ }
+
+ Row {
+ Repeater {
+ model: renderers
+ Column {
+ Shape {
+ preferredRendererType: renderer
+ width: 160
+ height: 150
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillColor: "red"
+
+ startX: 10; startY: 10
+ PathLine { relativeX: 140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: 100 }
+ PathLine { relativeX: -140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: -100 }
+ }
+ }
+
+ Shape {
+ preferredRendererType: renderer
+ width: 160
+ height: 150
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillColor: "red"
+
+ startX: 10; startY: 10 + 1 * 140
+ PathLine { relativeX: 140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: 100 }
+ PathLine { relativeX: -140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: -100 }
+ }
+ }
+
+ Shape {
+ preferredRendererType: renderer
+ width: 160
+ height: 150
+ Timer {
+ interval: 100
+ running: true
+ onTriggered: s.fillColor = Qt.rgba(0, 1, 0, 1)
+ }
+
+ ShapePath {
+ id: s
+ strokeColor: "transparent"
+ fillColor: "red"
+
+ startX: 10; startY: 10 + 2 * 140
+ PathLine { relativeX: 140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: 100 }
+ PathLine { relativeX: -140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: -100 }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/shape/shape_updatefill.qml b/tests/baseline/scenegraph/data/shape/shape_updatefill.qml
new file mode 100644
index 0000000000..8e034c7676
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shape/shape_updatefill.qml
@@ -0,0 +1,214 @@
+import QtQuick
+import QtQuick.Shapes
+
+Rectangle {
+ width: 320
+ height: 480
+ color: "lightgray"
+
+ ListModel {
+ id: renderers
+ ListElement { renderer: Shape.GeometryRenderer }
+ ListElement { renderer: Shape.CurveRenderer }
+ }
+
+ LinearGradient {
+ id: grad1
+ x2: 60; y2: 60
+ GradientStop { position: 0; color: "black" }
+ GradientStop { position: 1; color: "red" }
+ }
+
+ ConicalGradient {
+ id: grad2
+ centerX: 15; centerY: 15
+ GradientStop { position: 0; color: "yellow" }
+ GradientStop { position: .5; color: "black" }
+ GradientStop { position: 1; color: "yellow" }
+ }
+
+ Image {
+ id: img1
+ source: "../shared/world.png"
+ visible: false
+ }
+
+ Image {
+ id: img2
+ source: "../shared/sample_1.png"
+ visible: false
+ }
+
+ Row {
+ padding: 10
+ spacing: 20
+ Repeater {
+ model: renderers
+ Shape {
+ width: 140
+ preferredRendererType: renderer
+
+ ShapePath {
+ id: c1
+ strokeColor: "black"
+ fillColor: "cyan"
+ fillTransform: PlanarTransform.fromTranslate(rc1.x, rc1.y)
+
+ PathRectangle {
+ id: rc1
+ width: 60; height: 60
+ }
+ }
+
+ ShapePath {
+ id: c2
+ strokeColor: "black"
+ fillColor: "cyan"
+ fillTransform: PlanarTransform.fromTranslate(rc2.x, rc2.y)
+
+ PathRectangle {
+ id: rc2
+ x: 80
+ width: 60; height: 60
+ }
+ }
+
+ ShapePath {
+ id: g1
+ strokeColor: "black"
+ fillColor: "cyan"
+ fillTransform: PlanarTransform.fromTranslate(rg1.x, rg1.y)
+ fillGradient: grad1
+
+ PathRectangle {
+ id: rg1
+ y: 80
+ width: 60; height: 60
+ }
+ }
+
+ ShapePath {
+ id: t1
+ strokeColor: "black"
+ fillColor: "cyan"
+ fillItem: img1
+ fillTransform: PlanarTransform.fromTranslate(rt1.x, rt1.y)
+
+ PathRectangle {
+ id: rt1
+ x: 80; y: 80
+ width: 60; height: 60
+ }
+ }
+
+ ShapePath {
+ id: g2
+ strokeColor: "black"
+ fillColor: "cyan"
+ fillTransform: PlanarTransform.fromTranslate(rg2.x, rg2.y)
+ fillGradient: grad1
+
+ PathRectangle {
+ id: rg2
+ y: 2 * 80
+ width: 60; height: 60
+ }
+ }
+
+ ShapePath {
+ id: t2
+ strokeColor: "black"
+ fillColor: "cyan"
+ fillTransform: PlanarTransform.fromTranslate(rt2.x, rt2.y)
+ fillItem: img1
+
+ PathRectangle {
+ id: rt2
+ x: 80; y: 2 * 80
+ width: 60; height: 60
+ }
+ }
+
+ ShapePath {
+ id: g3
+ strokeColor: "black"
+ fillColor: "cyan"
+ fillTransform: PlanarTransform.fromTranslate(rg3.x, rg3.y)
+ fillGradient: grad1
+
+ PathRectangle {
+ id: rg3
+ y: 3 * 80
+ width: 60; height: 60
+ }
+ }
+
+ ShapePath {
+ id: t3
+ strokeColor: "black"
+ fillColor: "cyan"
+ fillTransform: PlanarTransform.fromTranslate(rt3.x, rt3.y)
+ fillItem: img1
+
+ PathRectangle {
+ id: rt3
+ x: 80; y: 3 * 80
+ width: 60; height: 60
+ }
+ }
+
+ ShapePath {
+ id: g4
+ strokeColor: "black"
+ fillColor: "cyan"
+ fillTransform: PlanarTransform.fromTranslate(rg4.x, rg4.y)
+ fillGradient: grad2
+
+ PathRectangle {
+ id: rg4
+ y: 4 * 80
+ width: 60; height: 60
+ }
+ }
+
+ ShapePath {
+ id: t4
+ strokeColor: "black"
+ fillColor: "cyan"
+ fillTransform: PlanarTransform.fromTranslate(rt4.x, rt4.y)
+ fillItem: img2
+
+ PathRectangle {
+ id: rt4
+ x: 80; y: 4 * 80
+ width: 60; height: 60
+ }
+ }
+
+ Timer {
+ running: true
+ interval: 150 // <200ms needed for scenegrabber; disable for manual testing
+ onTriggered: {
+ // Test all changes A->B, where A,B in {fillColor, fillGradient, fillItem}
+ // plus change of fillTransform
+
+ c1.fillGradient = grad1
+ g1.fillGradient = null
+ g2.fillGradient = null
+ g2.fillItem = img1
+ g3.fillGradient = grad2
+
+ c2.fillItem = img1
+ t1.fillItem = null
+ t2.fillGradient = grad1
+ t3.fillItem = img2
+
+ g4.fillTransform = g4.fillTransform.times(PlanarTransform.fromRotate(45, 30, 30))
+ t4.fillTransform = t4.fillTransform.times(PlanarTransform.fromRotate(45, 30, 30))
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/tests/baseline/scenegraph/data/shape/shape_updategradient.qml b/tests/baseline/scenegraph/data/shape/shape_updategradient.qml
new file mode 100644
index 0000000000..f1fa0f0f3d
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shape/shape_updategradient.qml
@@ -0,0 +1,105 @@
+import QtQuick
+import QtQuick.Shapes
+
+Item {
+ width: 320
+ height: 800
+
+ ListModel {
+ id: renderers
+ ListElement { renderer: Shape.GeometryRenderer }
+ ListElement { renderer: Shape.CurveRenderer }
+ }
+
+ RadialGradient {
+ id: radialGradient
+ centerX: 80
+ centerY: 75
+ centerRadius: centerY
+ focalX: centerX
+ focalY: centerY
+ GradientStop { position: 0; color: "black" }
+ GradientStop { position: .5; color: "cyan" }
+ GradientStop { position: 1; color: "black" }
+ }
+
+ Row {
+ Repeater {
+ model: renderers
+ Column {
+ Shape {
+ preferredRendererType: renderer
+ width: 160
+ height: 150
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillGradient: LinearGradient {
+ y1: 50; y2: 80
+ GradientStop { position: 0; color: "black" }
+ GradientStop { position: 1; color: "cyan" }
+ }
+ fillTransform: PlanarTransform.fromAffineMatrix(0.8, 0.2, 0.3, 1.5, 20, -50 + startY)
+
+ startX: 10; startY: 10
+ PathLine { relativeX: 140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: 100 }
+ PathLine { relativeX: -140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: -100 }
+ }
+ }
+
+ Shape {
+ preferredRendererType: renderer
+ width: 160
+ height: 150
+
+ ShapePath {
+ strokeColor: "transparent"
+ fillGradient: LinearGradient {
+ y1: 50; y2: 80
+ GradientStop { position: 0; color: "black" }
+ GradientStop { position: 1; color: "cyan" }
+ }
+ fillTransform: PlanarTransform.fromAffineMatrix(0.8, 0.2, 0.3, 1.5, 20, -50 + startY)
+
+ startX: 10; startY: 10 + 1 * 140
+ PathLine { relativeX: 140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: 100 }
+ PathLine { relativeX: -140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: -100 }
+ }
+ }
+
+ Shape {
+ preferredRendererType: renderer
+ width: 160
+ height: 150
+ Timer {
+ interval: 100
+ running: true
+ onTriggered: s.fillGradient = radialGradient
+ }
+
+ ShapePath {
+ id: s
+ strokeColor: "transparent"
+ fillGradient: LinearGradient {
+ y1: 50; y2: 80
+ GradientStop { position: 0; color: "black" }
+ GradientStop { position: 1; color: "cyan" }
+ }
+ fillTransform: PlanarTransform.fromAffineMatrix(0.8, 0.2, 0.3, 1.5, 20, -50 + startY)
+
+
+ startX: 10; startY: 10 + 2 * 140
+ PathLine { relativeX: 140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: 100 }
+ PathLine { relativeX: -140; relativeY: 0 }
+ PathLine { relativeX: 0; relativeY: -100 }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/shared/qt_logo.svg b/tests/baseline/scenegraph/data/shared/qt_logo.svg
new file mode 100644
index 0000000000..062daff3e9
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/qt_logo.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ width="462pt"
+ height="339pt"
+ viewBox="0 0 462 339"
+ version="1.1"
+ id="svg2"
+>
+ <path
+ fill="#41cd52"
+ d=" M 63.50 0.00 L 462.00 0.00 L 462.00 274.79 C 440.60 296.26 419.13 317.66 397.61 339.00 L 0.00 339.00 L 0.00 63.39 C 21.08 42.18 42.34 21.13 63.50 0.00 Z"
+ id="path6"/>
+ <path
+ d=" M 122.37 71.33 C 137.50 61.32 156.21 58.79 174.00 58.95 C 190.94 59.16 208.72 62.13 222.76 72.24 C 232.96 79.41 239.59 90.48 244.01 101.93 C 251.16 120.73 253.26 141.03 253.50 161.01 C 253.53 181.13 252.62 201.69 245.96 220.86 C 241.50 233.90 233.01 245.48 221.81 253.52 C 229.87 266.58 238.09 279.54 246.15 292.60 C 236.02 297.27 225.92 301.97 215.78 306.62 C 207.15 292.38 198.56 278.11 189.90 263.89 C 178.19 265.81 166.21 265.66 154.44 264.36 C 140.34 262.67 125.97 258.37 115.09 248.88 C 106.73 241.64 101.48 231.51 97.89 221.21 C 92.01 203.79 90.43 185.25 90.16 166.97 C 90.02 147.21 91.28 127.14 97.24 108.18 C 101.85 93.92 109.48 79.69 122.37 71.33 Z"
+ id="path8"
+ fill="#ffffff"/>
+ <path
+ d=" M 294.13 70.69 C 304.73 70.68 315.33 70.68 325.93 70.69 C 325.96 84.71 325.92 98.72 325.95 112.74 C 339.50 112.76 353.05 112.74 366.60 112.75 C 366.37 121.85 366.12 130.95 365.86 140.05 C 352.32 140.08 338.79 140.04 325.25 140.07 C 325.28 163.05 325.18 186.03 325.30 209.01 C 325.56 215.30 325.42 221.94 328.19 227.75 C 330.21 232.23 335.65 233.38 340.08 233.53 C 348.43 233.50 356.77 233.01 365.12 232.86 C 365.63 241.22 366.12 249.59 366.60 257.95 C 349.99 260.74 332.56 264.08 316.06 258.86 C 309.11 256.80 302.63 252.19 299.81 245.32 C 294.76 233.63 294.35 220.62 294.13 208.07 C 294.11 185.40 294.13 162.74 294.12 140.07 C 286.73 140.05 279.34 140.08 271.95 140.05 C 271.93 130.96 271.93 121.86 271.95 112.76 C 279.34 112.73 286.72 112.77 294.11 112.74 C 294.14 98.72 294.10 84.71 294.13 70.69 Z"
+ id="path10"
+ fill="#ffffff"/>
+ <path
+ fill="#41cd52"
+ d=" M 160.51 87.70 C 170.80 86.36 181.60 86.72 191.34 90.61 C 199.23 93.73 205.93 99.84 209.47 107.58 C 214.90 119.31 216.98 132.26 218.03 145.05 C 219.17 162.07 219.01 179.25 216.66 196.17 C 215.01 206.24 212.66 216.85 205.84 224.79 C 198.92 232.76 188.25 236.18 178.01 236.98 C 167.21 237.77 155.82 236.98 146.07 231.87 C 140.38 228.84 135.55 224.09 132.73 218.27 C 129.31 211.30 127.43 203.69 126.11 196.07 C 122.13 171.91 121.17 146.91 126.61 122.89 C 128.85 113.83 132.11 104.53 138.73 97.70 C 144.49 91.85 152.51 88.83 160.51 87.70 Z"
+ id="path12"/>
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg/gradientxform.svg b/tests/baseline/scenegraph/data/shared/svg/gradientxform.svg
new file mode 100644
index 0000000000..90eba14399
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg/gradientxform.svg
@@ -0,0 +1,62 @@
+<svg viewBox="0 0 380 800" xmlns="http://www.w3.org/2000/svg">
+ <radialGradient
+ id="gradient1"
+ gradientUnits="userSpaceOnUse"
+ cx="100"
+ cy="100"
+ r="100"
+ fx="100"
+ fy="100"
+ gradientTransform="translate(100 0)">
+ <stop offset="0%" stop-color="darkblue" />
+ <stop offset="50%" stop-color="skyblue" />
+ <stop offset="100%" stop-color="darkblue" />
+ </radialGradient>
+ <radialGradient
+ id="gradient2"
+ gradientUnits="userSpaceOnUse"
+ cx="100"
+ cy="100"
+ r="100"
+ fx="100"
+ fy="100"
+ gradientTransform="scale(2 1)">
+ <stop offset="0%" stop-color="darkblue" />
+ <stop offset="50%" stop-color="skyblue" />
+ <stop offset="100%" stop-color="darkblue" />
+ </radialGradient>
+ <radialGradient
+ id="gradient3"
+ gradientUnits="userSpaceOnUse"
+ cx="100"
+ cy="100"
+ r="100"
+ fx="100"
+ fy="100"
+ gradientTransform="skewX(40)">
+ <stop offset="0%" stop-color="darkblue" />
+ <stop offset="50%" stop-color="skyblue" />
+ <stop offset="100%" stop-color="darkblue" />
+ </radialGradient>
+
+ <rect x="0" y="0" width="300" height="100" fill="url(#gradient1)" />
+ <text font-size="124" x="0" y="200" stroke="black" fill="url(#gradient1)">XLAT</text>
+
+ <g transform="translate(0 250)">
+ <rect x="0" y="0" width="300" height="100" fill="url(#gradient2)" />
+ <text font-size="124" x="0" y="200" stroke="black" fill="url(#gradient2)">SCAL</text>
+ </g>
+
+ <g transform="translate(0 500)">
+ <rect x="0" y="0" width="300" height="100" fill="url(#gradient3)" />
+ <text font-size="124" x="0" y="200" stroke="black" fill="url(#gradient3)">SKEW</text>
+ </g>
+
+ <!--
+ <g font-family="Arial" font-size="92" transform="translate(50 0)">
+ <text x="0" y="100" stroke="black" fill="url(#gradient1)">TEST</text>
+ </g>
+-->
+</svg>
+
+
diff --git a/tests/baseline/scenegraph/data/shared/svg/text_stroking.svg b/tests/baseline/scenegraph/data/shared/svg/text_stroking.svg
new file mode 100644
index 0000000000..a5153c7087
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg/text_stroking.svg
@@ -0,0 +1,23 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="550" height="450">
+<!--Testing different values of stroke-linejoin-->
+ <g transform="translate(5, 70)">
+ <rect y="-55" width="250" height="210" fill="none" stroke="black" stroke-width="1"/>
+ <text y="0" style="font-size: 60px; font-weight: bold; font-family: sans-serif; fill: peachpuff; stroke: black; stroke-width:3.1px; stroke-linejoin: bevel">QtQuick</text>
+ <text y="70" style="font-size: 60px; font-weight: bold; font-family: sans-serif; fill: peachpuff; stroke: black; stroke-width:3.1px; stroke-linejoin: miter">QtQuick</text>
+ <text y="140" style="font-size: 60px; font-weight: bold; font-family: sans-serif; fill: peachpuff; stroke: black; stroke-width:3.1px; stroke-linejoin: round">QtQuick</text>
+ </g>
+<!--Testing dash arrays with different values for stroke-linecap-->
+ <g transform="translate(5, 280)">
+ <rect y="-55" width="250" height="210" fill="none" stroke="black" stroke-width="1"/>
+ <text style="font-size: 60; font-weight: bold; font-family: sans-serif; stroke-dasharray:3,5; fill: peachpuff; stroke: black; stroke-width:3.1px; stroke-linecap: square;">QtQuick</text>
+ <text y="70" style="font-size: 60; font-weight: bold; font-family: sans-serif; stroke-dasharray:3,5; fill: peachpuff; stroke: black; stroke-width:3.1px; stroke-linecap: round">QtQuick</text>
+ <text y="140" style="font-size: 60; font-weight: bold; font-family: sans-serif; stroke-dasharray:3,5; fill: peachpuff; stroke: black; stroke-width:3.1px; stroke-linecap: butt">QtQuick</text>
+ </g>
+<!--Testing dash arrays and dash offsets-->
+ <g transform="translate(270, 70)">
+ <rect y="-55" width="250" height="210" fill="none" stroke="black" stroke-width="1"/>
+ <text style="font-size: 60; font-weight: bold; font-family: sans-serif; stroke-dasharray:0; fill: peachpuff; stroke: black; stroke-width:3.1px; stroke-linecap: square;">QtQuick</text>
+ <text y="70" style="font-size: 60; font-weight: bold; font-family: sans-serif; stroke-dasharray:3, 5; fill: peachpuff; stroke: black; stroke-width:3.1px; stroke-linecap: square">QtQuick</text>
+ <text y="140" style="font-size: 60; font-weight: bold; font-family: sans-serif; stroke-dasharray:3,5; stroke-dashoffset:3; fill: peachpuff; stroke: black; stroke-width:3.1px; stroke-linecap: square">QtQuick</text>
+ </g>
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-constr-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-constr-201-t.svg
new file mode 100644
index 0000000000..7d922a30b6
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-constr-201-t.svg
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="AE" desc="Tests constrained transformations" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: coords-constr-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test Constrained Transformations
+ There are three lines of text in this test.
+ The first is not constrained.
+ The second is constrained with a x and y offset.
+ The third is constrained.
+ The test will pass if, after applying user agent transforms, the circles behave as defined.
+ The test will pass if the three circles align vertically.
+ The reference image displays the file after performing a user agent zoom.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-constr-201-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="10">
+
+ <g xml:id="reference" stroke="none">
+ <rect x="15" y="15" height="270" width="450" fill="none" stroke="black" stroke-width="0.25"/>
+ <text xml:id="display-title" x="240" y="50" text-anchor="middle" font-size="16" fill="#000">Constrained Transformations</text>
+ </g>
+ <g fill="blue" stroke="none">
+ <circle cx="50" cy="105" r="15"/>
+ <text x="70" y="115" font-size="12">Can be panned, rotated and scaled by the user agent transform.</text>
+ </g>
+ <g transform="ref(svg,10,10)" fill="blue">
+ <circle cx="40" cy="150" r="15"/>
+ <text x="60" y="160" stroke="none" font-size="12">Cannot be transformed by the user agent transform.</text>
+ </g>
+ <g transform="ref(svg)">
+ <circle cx="50" cy="215" r="15" fill="blue"/>
+ <text x="70" y="225" fill="blue" font-size="12">Cannot be transformed by the user agent transform.</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-coord-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-coord-01-t.svg
new file mode 100644
index 0000000000..bf0ba5a2a6
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-coord-01-t.svg
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/" reviewer="DJ" owner="CN" desc="Tests the default initial coordinate system used by renderer." status="accepted" approved="yes" version="$Revision: 1.6 $" testname="$RCSfile: coords-coord-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Tests the default initial coordinate system used by renderer. Should be 0,0 if not specified.This is illustrated by comparing red boxes that are missing a coordinate or all coordinates with yellow boxes that have the correct coordinates specified. This test should produce three red boxes, with small yellow boxes rendered on top of them. These boxes should be placed along the origin, and x and y axis.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-coord-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- Content of Test Case follows. -->
+ <g stroke="black" stroke-width="5">
+ <line x1="0" y1="0" x2="150" y2="0" />
+ <line x1="0" y1="0" x2="0" y2="150" />
+ </g>
+ <g fill="red">
+ <rect width="15" height="15" />
+ <rect x="150" width="15" height="15" />
+ <rect y="150" width="15" height="15" />
+ </g>
+ <g fill="yellow">
+ <rect x="0" y="0" width="10" height="10" />
+ <rect x="150" y="0" width="10" height="10" />
+ <rect x="0" y="150" width="10" height="10" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-01-t.svg
new file mode 100644
index 0000000000..097423b02b
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-01-t.svg
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="VH" desc="Validates elementary transforms and transformation nesting" status="accepted"
+ approved="yes"
+ version="$Revision: 1.10 $" testname="$RCSfile: coords-trans-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test verifies the implementation of transforms. It tests elementary transforms and transform nesting. Note that for layout purposes, this test uses nesting of translation with the elementary transforms.</p>
+ <p>The rendered picture should match the reference image exactly except for variations in the labeling text.</p>
+ <p>The test uses the rect element, the fill color (solid primary colors) and transforms.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-trans-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="translate(0, 30)" font-size="13">
+ <!-- ====================================================================== -->
+ <!-- First, draw a test grid ============================================== -->
+ <!-- ====================================================================== -->
+ <g xml:id="test-grid" stroke="#cccccc" stroke-width="1">
+ <line x1="10" y1="10.5" x2="470" y2="10.5" />
+ <line x1="10" y1="20.5" x2="470" y2="20.5" />
+ <line x1="10" y1="30.5" x2="470" y2="30.5" />
+ <line x1="10" y1="40.5" x2="470" y2="40.5" />
+ <line x1="10" y1="50.5" x2="470" y2="50.5" />
+ <line x1="10" y1="60.5" x2="470" y2="60.5" />
+ <line x1="10" y1="70.5" x2="470" y2="70.5" />
+ <line x1="10" y1="80.5" x2="470" y2="80.5" />
+ <line x1="10" y1="90.5" x2="470" y2="90.5" />
+ <line x1="10" y1="100.5" x2="470" y2="100.5" />
+ <line x1="10" y1="110.5" x2="470" y2="110.5" />
+ <line x1="10" y1="120.5" x2="470" y2="120.5" />
+ <line x1="10" y1="130.5" x2="470" y2="130.5" />
+ <line x1="10" y1="140.5" x2="470" y2="140.5" />
+ <line x1="10" y1="150.5" x2="470" y2="150.5" />
+ <line x1="10" y1="160.5" x2="470" y2="160.5" />
+ <line x1="10" y1="170.5" x2="470" y2="170.5" />
+ <line x1="10" y1="180.5" x2="470" y2="180.5" />
+ <line x1="10" y1="190.5" x2="470" y2="190.5" />
+ <line x1="10" y1="200.5" x2="470" y2="200.5" />
+ <line x1="10" y1="210.5" x2="470" y2="210.5" />
+ <line x1="10" y1="220.5" x2="470" y2="220.5" />
+ <line x1="10" y1="230.5" x2="470" y2="230.5" />
+ <line x1="10" y1="240.5" x2="470" y2="240.5" />
+ <line x1="10" y1="250.5" x2="470" y2="250.5" />
+ <line x1="10" y1="260.5" x2="470" y2="260.5" />
+ <line y1="10" x1="10.5" y2="260.5" x2="10.5" />
+ <line y1="10" x1="20.5" y2="260.5" x2="20.5" />
+ <line y1="10" x1="30.5" y2="260.5" x2="30.5" />
+ <line y1="10" x1="40.5" y2="260.5" x2="40.5" />
+ <line y1="10" x1="50.5" y2="260.5" x2="50.5" />
+ <line y1="10" x1="60.5" y2="260.5" x2="60.5" />
+ <line y1="10" x1="70.5" y2="260.5" x2="70.5" />
+ <line y1="10" x1="80.5" y2="260.5" x2="80.5" />
+ <line y1="10" x1="90.5" y2="260.5" x2="90.5" />
+ <line y1="10" x1="100.5" y2="260.5" x2="100.5" />
+ <line y1="10" x1="110.5" y2="260.5" x2="110.5" />
+ <line y1="10" x1="120.5" y2="260.5" x2="120.5" />
+ <line y1="10" x1="130.5" y2="260.5" x2="130.5" />
+ <line y1="10" x1="140.5" y2="260.5" x2="140.5" />
+ <line y1="10" x1="150.5" y2="260.5" x2="150.5" />
+ <line y1="10" x1="160.5" y2="260.5" x2="160.5" />
+ <line y1="10" x1="170.5" y2="260.5" x2="170.5" />
+ <line y1="10" x1="180.5" y2="260.5" x2="180.5" />
+ <line y1="10" x1="190.5" y2="260.5" x2="190.5" />
+ <line y1="10" x1="200.5" y2="260.5" x2="200.5" />
+ <line y1="10" x1="210.5" y2="260.5" x2="210.5" />
+ <line y1="10" x1="220.5" y2="260.5" x2="220.5" />
+ <line y1="10" x1="230.5" y2="260.5" x2="230.5" />
+ <line y1="10" x1="240.5" y2="260.5" x2="240.5" />
+ <line y1="10" x1="250.5" y2="260.5" x2="250.5" />
+ <line y1="10" x1="260.5" y2="260.5" x2="260.5" />
+ <line y1="10" x1="270.5" y2="260.5" x2="270.5" />
+ <line y1="10" x1="280.5" y2="260.5" x2="280.5" />
+ <line y1="10" x1="290.5" y2="260.5" x2="290.5" />
+ <line y1="10" x1="300.5" y2="260.5" x2="300.5" />
+ <line y1="10" x1="310.5" y2="260.5" x2="310.5" />
+ <line y1="10" x1="320.5" y2="260.5" x2="320.5" />
+ <line y1="10" x1="330.5" y2="260.5" x2="330.5" />
+ <line y1="10" x1="340.5" y2="260.5" x2="340.5" />
+ <line y1="10" x1="350.5" y2="260.5" x2="350.5" />
+ <line y1="10" x1="360.5" y2="260.5" x2="360.5" />
+ <line y1="10" x1="370.5" y2="260.5" x2="370.5" />
+ <line y1="10" x1="380.5" y2="260.5" x2="380.5" />
+ <line y1="10" x1="390.5" y2="260.5" x2="390.5" />
+ <line y1="10" x1="400.5" y2="260.5" x2="400.5" />
+ <line y1="10" x1="410.5" y2="260.5" x2="410.5" />
+ <line y1="10" x1="420.5" y2="260.5" x2="420.5" />
+ <line y1="10" x1="430.5" y2="260.5" x2="430.5" />
+ <line y1="10" x1="440.5" y2="260.5" x2="440.5" />
+ <line y1="10" x1="450.5" y2="260.5" x2="450.5" />
+ <line y1="10" x1="460.5" y2="260.5" x2="460.5" />
+ <line y1="10" x1="470.5" y2="260.5" x2="470.5" />
+ </g>
+ <!-- ====================================================================== -->
+ <!-- Now, test elementary transforms. For each transform, 3 markers are -->
+ <!-- placed where the user space is expected after transformations for the -->
+ <!-- origin (black) and the points in (20, 0) (blue) and (0, 20) (red). -->
+ <!-- Then, a blue line going from (0, 0) to (20, 0) is drawn and a red line -->
+ <!-- going from (0, 0) to (0, 20), after applying the elementary -->
+ <!-- transformation. If the test succeeds, the red line should join the -->
+ <!-- black marker to the red marker and the blue line the black marker to -->
+ <!-- the blue marker. -->
+ <!-- ====================================================================== -->
+ <g xml:id="elementary-transforms-test" transform="translate(0, 10)">
+ <g xml:id="elementary-transforms">
+ <!-- Translate -->
+ <g transform="translate(50, 50)">
+ <rect x="0" y="0" width="20" height="2" fill="blue" />
+ <rect x="0" y="0" width="2" height="20" fill="red" />
+ </g>
+ <!-- Rotate -90 deg about (150, 70) -->
+ <g transform="translate(150, 70) rotate(-90)">
+ <rect x="0" y="0" width="20" height="2" fill="blue" />
+ <rect x="0" y="0" width="2" height="20" fill="red" />
+ </g>
+ <!-- Skew X -->
+ <g transform="translate(250, 50) skewX(45)">
+ <rect x="0" y="0" width="20" height="2" fill="blue" />
+ <rect x="0" y="0" width="2" height="20" fill="red" />
+ </g>
+ <!-- Skew Y -->
+ <g transform="translate(350, 50) skewY(45)">
+ <rect x="0" y="0" width="20" height="2" fill="blue" />
+ <rect x="0" y="0" width="2" height="20" fill="red" />
+ </g>
+ <!-- Scale 2 -->
+ <g transform="translate(210, 120) scale(2)">
+ <rect x="0" y="0" width="20" height="1" fill="blue" />
+ <rect x="0" y="0" width="1" height="20" fill="red" />
+ </g>
+ </g>
+ <!-- elementary-transforms -->
+ <!-- Draw all the markers -->
+ <g xml:id="elementary-transforms-test-markers">
+ <!-- Translate -->
+ <text x="40" y="40">translate (50, 50)</text>
+ <rect x="48" y="48" width="5" height="5" fill="black" />
+ <rect x="68" y="48" width="5" height="5" fill="blue" />
+ <rect x="48" y="68" width="5" height="5" fill="red" />
+ <!-- Rotate -90 deg about (150, 70) -->
+ <text x="140" y="40">rotate(-90)</text>
+ <rect x="148" y="68" width="5" height="5" fill="black" />
+ <rect x="148" y="48" width="5" height="5" fill="blue" />
+ <rect x="168" y="68" width="5" height="5" fill="red" />
+ <!-- Skew X -->
+ <text x="240" y="40">skew x (45)</text>
+ <rect x="248" y="48" width="5" height="5" fill="black" />
+ <rect x="268" y="48" width="5" height="5" fill="blue" />
+ <rect x="268" y="68" width="5" height="5" fill="red" />
+ <!-- Skew Y -->
+ <text x="340" y="40">skew y (45)</text>
+ <rect x="348" y="48" width="5" height="5" fill="black" />
+ <rect x="368" y="68" width="5" height="5" fill="blue" />
+ <rect x="348" y="68" width="5" height="5" fill="red" />
+ <!-- Scale 2 -->
+ <text x="200" y="110">scale (2)</text>
+ <rect x="208" y="118" width="5" height="5" fill="black" />
+ <rect x="248" y="118" width="5" height="5" fill="blue" />
+ <rect x="208" y="158" width="5" height="5" fill="red" />
+ </g>
+ <!-- elementary-transforms-test-markers -->
+ </g>
+ <g xml:id="nested-transforms-test">
+ <g xml:id="nested-transforms">
+ <!-- scale/translate in transform attribute -->
+ <g transform="scale(3, 2) translate(16.666667, 105)">
+ <rect x="0" y="0" width="20" height="1" fill="blue" />
+ <rect x="0" y="0" width="0.67" height="20" fill="red" />
+ </g>
+ <!-- scale/translate in successive elements -->
+ <g transform="translate(200, 0)">
+ <g transform="scale(3, 2)">
+ <g transform="translate(16.666667, 105)">
+ <rect x="0" y="0" width="20" height="1" fill="blue" />
+ <rect x="0" y="0" width="0.67" height="20" fill="red" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <!-- nested-transforms -->
+ <g xml:id="nested-transforms-test-markers">
+ <!-- scale and translate -->
+ <text x="40" y="200">scale(25, 95) and translate(2, 2)</text>
+ <rect x="48" y="208" width="5" height="5" fill="black" />
+ <rect x="108" y="208" width="5" height="5" fill="blue" />
+ <rect x="48" y="248" width="5" height="5" fill="red" />
+ <!-- scale then translate -->
+ <text x="240" y="200">scale(25, 95) then translate(2, 2)</text>
+ <rect x="248" y="208" width="5" height="5" fill="black" />
+ <rect x="308" y="208" width="5" height="5" fill="blue" />
+ <rect x="248" y="248" width="5" height="5" fill="red" />
+ </g>
+ <!-- nested-transforms-test-markers -->
+ </g>
+ <!-- nested-transforms test -->
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-02-t.svg
new file mode 100644
index 0000000000..806d0c4dcd
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-02-t.svg
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="VH" desc="Validates elementary transforms and transformation nesting" status="accepted"
+ approved="yes"
+ version="$Revision: 1.10 $" testname="$RCSfile: coords-trans-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test verifies the implementation of transforms. It tests elementary transforms and transform nesting. Note that for layout purposes, this test uses nesting of translation with the elementary transforms.</p>
+ <p>The rendered picture should match the reference image exactly except for variations in the labeling text.</p>
+ <p>The test uses the rect element, the fill color (solid primary colors) and transforms.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-trans-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="translate(0, 30)" font-size="12">
+ <!-- ====================================================================== -->
+ <!-- First, draw a test grid ============================================== -->
+ <!-- ====================================================================== -->
+ <!--g xml:id="test-grid" stroke="#cccccc" stroke-width="1" > <line x1="10" y1="10.5" x2="470" y2="10.5"/> <line x1="10" y1="20.5" x2="470" y2="20.5"/> <line x1="10" y1="30.5" x2="470" y2="30.5"/> <line x1="10" y1="40.5" x2="470" y2="40.5"/> <line x1="10" y1="50.5" x2="470" y2="50.5"/> <line x1="10" y1="60.5" x2="470" y2="60.5"/> <line x1="10" y1="70.5" x2="470" y2="70.5"/> <line x1="10" y1="80.5" x2="470" y2="80.5"/> <line x1="10" y1="90.5" x2="470" y2="90.5"/> <line x1="10" y1="100.5" x2="470" y2="100.5"/> <line x1="10" y1="110.5" x2="470" y2="110.5"/> <line x1="10" y1="120.5" x2="470" y2="120.5"/> <line x1="10" y1="130.5" x2="470" y2="130.5"/> <line x1="10" y1="140.5" x2="470" y2="140.5"/> <line x1="10" y1="150.5" x2="470" y2="150.5"/> <line x1="10" y1="160.5" x2="470" y2="160.5"/> <line x1="10" y1="170.5" x2="470" y2="170.5"/> <line x1="10" y1="180.5" x2="470" y2="180.5"/> <line x1="10" y1="190.5" x2="470" y2="190.5"/> <line x1="10" y1="200.5" x2="470" y2="200.5"/> <line x1="10" y1="210.5" x2="470" y2="210.5"/> <line x1="10" y1="220.5" x2="470" y2="220.5"/> <line x1="10" y1="230.5" x2="470" y2="230.5"/> <line x1="10" y1="240.5" x2="470" y2="240.5"/> <line x1="10" y1="250.5" x2="470" y2="250.5"/> <line x1="10" y1="260.5" x2="470" y2="260.5"/> <line y1="10" x1="10.5" y2="260.5" x2="10.5"/> <line y1="10" x1="20.5" y2="260.5" x2="20.5"/> <line y1="10" x1="30.5" y2="260.5" x2="30.5"/> <line y1="10" x1="40.5" y2="260.5" x2="40.5"/> <line y1="10" x1="50.5" y2="260.5" x2="50.5"/> <line y1="10" x1="60.5" y2="260.5" x2="60.5"/> <line y1="10" x1="70.5" y2="260.5" x2="70.5"/> <line y1="10" x1="80.5" y2="260.5" x2="80.5"/> <line y1="10" x1="90.5" y2="260.5" x2="90.5"/> <line y1="10" x1="100.5" y2="260.5" x2="100.5"/> <line y1="10" x1="110.5" y2="260.5" x2="110.5"/> <line y1="10" x1="120.5" y2="260.5" x2="120.5"/> <line y1="10" x1="130.5" y2="260.5" x2="130.5"/> <line y1="10" x1="140.5" y2="260.5" x2="140.5"/> <line y1="10" x1="150.5" y2="260.5" x2="150.5"/> <line y1="10" x1="160.5" y2="260.5" x2="160.5"/> <line y1="10" x1="170.5" y2="260.5" x2="170.5"/> <line y1="10" x1="180.5" y2="260.5" x2="180.5"/> <line y1="10" x1="190.5" y2="260.5" x2="190.5"/> <line y1="10" x1="200.5" y2="260.5" x2="200.5"/> <line y1="10" x1="210.5" y2="260.5" x2="210.5"/> <line y1="10" x1="220.5" y2="260.5" x2="220.5"/> <line y1="10" x1="230.5" y2="260.5" x2="230.5"/> <line y1="10" x1="240.5" y2="260.5" x2="240.5"/> <line y1="10" x1="250.5" y2="260.5" x2="250.5"/> <line y1="10" x1="260.5" y2="260.5" x2="260.5"/> <line y1="10" x1="270.5" y2="260.5" x2="270.5"/> <line y1="10" x1="280.5" y2="260.5" x2="280.5"/> <line y1="10" x1="290.5" y2="260.5" x2="290.5"/> <line y1="10" x1="300.5" y2="260.5" x2="300.5"/> <line y1="10" x1="310.5" y2="260.5" x2="310.5"/> <line y1="10" x1="320.5" y2="260.5" x2="320.5"/> <line y1="10" x1="330.5" y2="260.5" x2="330.5"/> <line y1="10" x1="340.5" y2="260.5" x2="340.5"/> <line y1="10" x1="350.5" y2="260.5" x2="350.5"/> <line y1="10" x1="360.5" y2="260.5" x2="360.5"/> <line y1="10" x1="370.5" y2="260.5" x2="370.5"/> <line y1="10" x1="380.5" y2="260.5" x2="380.5"/> <line y1="10" x1="390.5" y2="260.5" x2="390.5"/> <line y1="10" x1="400.5" y2="260.5" x2="400.5"/> <line y1="10" x1="410.5" y2="260.5" x2="410.5"/> <line y1="10" x1="420.5" y2="260.5" x2="420.5"/> <line y1="10" x1="430.5" y2="260.5" x2="430.5"/> <line y1="10" x1="440.5" y2="260.5" x2="440.5"/> <line y1="10" x1="450.5" y2="260.5" x2="450.5"/> <line y1="10" x1="460.5" y2="260.5" x2="460.5"/> <line y1="10" x1="470.5" y2="260.5" x2="470.5"/> </g-->
+ <!-- ====================================================================== -->
+ <!-- Now, test elementary transforms. For each transform, 3 markers are -->
+ <!-- placed where the user space is expected after transformations for the -->
+ <!-- origin (black) and the points in (20, 0) (blue) and (0, 20) (red). -->
+ <!-- Then, a blue line going from (0, 0) to (20, 0) is drawn and a red line -->
+ <!-- going from (0, 0) to (0, 20), after applying the elementary -->
+ <!-- transformation. If the test succeeds, the red line should join the -->
+ <!-- black marker to the red marker and the blue line the black marker to -->
+ <!-- the blue marker. -->
+ <!-- ====================================================================== -->
+ <g xml:id="elementary-transforms-test" transform="translate(0, 10)">
+ <g xml:id="elementary-transforms" transform="translate(-30, 0) scale(2.5, 2.5)">
+ <!-- Translate -->
+ <g transform="translate(50, 50)">
+ <rect x="0" y="0" width="20" height="2" fill="blue" />
+ <rect x="0" y="0" width="2" height="20" fill="red" />
+ </g>
+ <!-- Rotate -90 deg about (150, 70) -->
+ <g transform="translate(150, 70) rotate(-90)">
+ <rect x="0" y="0" width="20" height="2" fill="blue" />
+ <rect x="0" y="0" width="2" height="20" fill="red" />
+ </g>
+ </g>
+ <!-- elementary-transforms -->
+ <!-- Draw all the markers -->
+ <g xml:id="elementary-transforms-test-markers" transform="translate(-30, 0) scale(2.5, 2.5)">
+ <!-- Translate -->
+ <text x="40" y="40">translate (50, 50)</text>
+ <rect x="48" y="48" width="5" height="5" fill="black" />
+ <rect x="68" y="48" width="5" height="5" fill="blue" />
+ <rect x="48" y="68" width="5" height="5" fill="red" />
+ <!-- Rotate -90 deg about (150, 70) -->
+ <text x="140" y="40">rotate(-90)</text>
+ <rect x="148" y="68" width="5" height="5" fill="black" />
+ <rect x="148" y="48" width="5" height="5" fill="blue" />
+ <rect x="168" y="68" width="5" height="5" fill="red" />
+ </g>
+ <!-- elementary-transforms-test-markers -->
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-03-t.svg
new file mode 100644
index 0000000000..8d1952033e
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-03-t.svg
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="VH" desc="Validates elementary transforms and transformation nesting"
+ status="accepted"
+ approved="yes" version="$Revision: 1.9 $" testname="$RCSfile: coords-trans-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test verifies the implementation of transforms. It tests elementary transforms and transform nesting. Note that for layout purposes, this test uses nesting of translation with the elementary transforms.</p>
+ <p>The rendered picture should match the reference image exactly except for variations in the labeling text.</p>
+ <p>The test uses the rect element, the fill color (solid primary colors) and transforms.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-trans-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="translate(0, 30)" font-size="12">
+ <!-- ====================================================================== -->
+ <!-- Now, test elementary transforms. For each transform, 3 markers are -->
+ <!-- placed where the user space is expected after transformations for the -->
+ <!-- origin (black) and the points in (20, 0) (blue) and (0, 20) (red). -->
+ <!-- Then, a blue line going from (0, 0) to (20, 0) is drawn and a red line -->
+ <!-- going from (0, 0) to (0, 20), after applying the elementary -->
+ <!-- transformation. If the test succeeds, the red line should join the -->
+ <!-- black marker to the red marker and the blue line the black marker to -->
+ <!-- the blue marker. -->
+ <!-- ====================================================================== -->
+ <g xml:id="elementary-transforms-test" transform="translate(0, 10)">
+ <g xml:id="elementary-transforms" transform="translate(-560, 0) scale(2.5, 2.5)">
+ <!-- Skew X -->
+ <g transform="translate(250, 50) skewX(45)">
+ <rect x="0" y="0" width="20" height="2" fill="blue" />
+ <rect x="0" y="0" width="2" height="20" fill="red" />
+ </g>
+ <!-- Skew Y -->
+ <g transform="translate(350, 50) skewY(45)">
+ <rect x="0" y="0" width="20" height="2" fill="blue" />
+ <rect x="0" y="0" width="2" height="20" fill="red" />
+ </g>
+ </g>
+ <!-- elementary-transforms -->
+ <!-- Draw all the markers -->
+ <g xml:id="elementary-transforms-test-markers" transform="translate(-560, 0) scale(2.5, 2.5)">
+ <!-- Skew X -->
+ <text x="240" y="40">skew x (45)</text>
+ <rect x="248" y="48" width="5" height="5" fill="black" />
+ <rect x="268" y="48" width="5" height="5" fill="blue" />
+ <rect x="268" y="68" width="5" height="5" fill="red" />
+ <!-- Skew Y -->
+ <text x="340" y="40">skew y (45)</text>
+ <rect x="348" y="48" width="5" height="5" fill="black" />
+ <rect x="368" y="68" width="5" height="5" fill="blue" />
+ <rect x="348" y="68" width="5" height="5" fill="red" />
+ </g>
+ <!-- elementary-transforms-test-markers -->
+ </g>
+ <!-- nested-transforms test -->
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-04-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-04-t.svg
new file mode 100644
index 0000000000..f3bd5f32bf
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-04-t.svg
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="VH" desc="Validates elementary transforms and transformation nesting"
+ status="accepted"
+ approved="yes" version="$Revision: 1.9 $" testname="$RCSfile: coords-trans-04-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test verifies the implementation of transforms. It tests elementary transforms and transform nesting. Note that for layout purposes, this test uses nesting of translation with the elementary transforms.</p>
+ <p>The rendered picture should match the reference image exactly except for variations in the labeling text.</p>
+ <p>The test uses the rect element, the fill color (solid primary colors) and transforms.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-trans-04-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="translate(0, 30)" font-size="12">
+ <!-- ====================================================================== -->
+ <!-- Now, test elementary transforms. For each transform, 3 markers are -->
+ <!-- placed where the user space is expected after transformations for the -->
+ <!-- origin (black) and the points in (20, 0) (blue) and (0, 20) (red). -->
+ <!-- Then, a blue line going from (0, 0) to (20, 0) is drawn and a red line -->
+ <!-- going from (0, 0) to (0, 20), after applying the elementary -->
+ <!-- transformation. If the test succeeds, the red line should join the -->
+ <!-- black marker to the red marker and the blue line the black marker to -->
+ <!-- the blue marker. -->
+ <!-- ====================================================================== -->
+ <g xml:id="elementary-transforms-test">
+ <g xml:id="elementary-transforms" transform="translate(60, 45) scale(2.5, 2.5)">
+ <!-- Scale 2 -->
+ <g transform="translate(40, 10) scale(2)">
+ <rect x="0" y="0" width="20" height="1" fill="blue" />
+ <rect x="0" y="0" width="1" height="20" fill="red" />
+ </g>
+ </g>
+ <!-- elementary-transforms -->
+ <!-- Draw all the markers -->
+ <g xml:id="elementary-transforms-test-markers" transform="translate(-364, -230) scale(2.5, 2.5)">
+ <!-- Scale 2 -->
+ <text x="200" y="110">scale (2)</text>
+ <rect x="208" y="118" width="5" height="5" fill="black" />
+ <rect x="248" y="118" width="5" height="5" fill="blue" />
+ <rect x="208" y="158" width="5" height="5" fill="red" />
+ </g>
+ <!-- elementary-transforms-test-markers -->
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-05-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-05-t.svg
new file mode 100644
index 0000000000..bef79c291f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-05-t.svg
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="VH" desc="Validates elementary transforms and transformation nesting" status="accepted"
+ approved="yes"
+ version="$Revision: 1.9 $" testname="$RCSfile: coords-trans-05-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test verifies the implementation of transforms. It tests elementary transforms and transform nesting. Note that for layout purposes, this test uses nesting of translation with the elementary transforms.</p>
+ <p>The rendered picture should match the reference image exactly except for variations in the labeling text.</p>
+ <p>The test uses the rect element, the fill color (solid primary colors) and transforms.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-trans-05-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="translate(0, 30)" font-size="12">
+ <!-- ====================================================================== -->
+ <!-- Now, test elementary transforms. For each transform, 3 markers are -->
+ <!-- placed where the user space is expected after transformations for the -->
+ <!-- origin (black) and the points in (20, 0) (blue) and (0, 20) (red). -->
+ <!-- Then, a blue line going from (0, 0) to (20, 0) is drawn and a red line -->
+ <!-- going from (0, 0) to (0, 20), after applying the elementary -->
+ <!-- transformation. If the test succeeds, the red line should join the -->
+ <!-- black marker to the red marker and the blue line the black marker to -->
+ <!-- the blue marker. -->
+ <!-- ====================================================================== -->
+ <g xml:id="nested-transforms-test">
+ <g xml:id="nested-transforms" transform="translate(-90, -450)">
+ <!-- scale/translate in transform attribute -->
+ <g transform="scale(7.5, 5) translate(16.666667, 105)">
+ <rect x="0" y="0" width="20" height="1" fill="blue" />
+ <rect x="0" y="0" width="0.67" height="20" fill="red" />
+ </g>
+ </g>
+ <!-- nested-transforms -->
+ <g xml:id="nested-transforms-test-markers" transform="translate(-90, -450) scale(2.5, 2.5)">
+ <!-- scale and translate -->
+ <text x="40" y="200">scale(25, 95) - translate(2, 2)</text>
+ <rect x="48" y="208" width="5" height="5" fill="black" />
+ <rect x="108" y="208" width="5" height="5" fill="blue" />
+ <rect x="48" y="248" width="5" height="5" fill="red" />
+ </g>
+ <!-- nested-transforms-test-markers -->
+ </g>
+ <!-- nested-transforms test -->
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-06-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-06-t.svg
new file mode 100644
index 0000000000..3b96343b68
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-06-t.svg
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="VH" desc="Validates elementary transforms and transformation nesting"
+ status="accepted"
+ approved="yes" version="$Revision: 1.10 $" testname="$RCSfile: coords-trans-06-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test verifies the implementation of transforms. It tests elementary transforms and transform nesting. Note that for layout purposes, this test uses nesting of translation with the elementary transforms.</p>
+ <p>The rendered picture should match the reference image exactly except for variations in the labeling text.</p>
+ <p>The test uses the rect element, the fill color (solid primary colors) and transforms.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-trans-06-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="translate(0, 30)" font-size="12">
+ <g xml:id="nested-transforms-test">
+ <g xml:id="nested-transforms">
+ <!-- scale/translate in successive elements -->
+ <g transform="translate(-102, -450)">
+ <g transform="scale(7.5, 5)">
+ <g transform="translate(16.666667, 105)">
+ <rect x="0" y="0" width="20" height="1" fill="blue" />
+ <rect x="0" y="0" width="0.67" height="20" fill="red" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <!-- nested-transforms -->
+ <g xml:id="nested-transforms-test-markers" transform="translate(-600, -450) scale(2.5, 2.5)">
+ <!-- scale then translate -->
+ <text x="248" y="200">scale(25, 95) then translate(2, 2)</text>
+ <rect x="248" y="208" width="5" height="5" fill="black" />
+ <rect x="308" y="208" width="5" height="5" fill="blue" />
+ <rect x="248" y="248" width="5" height="5" fill="red" />
+ </g>
+ <!-- nested-transforms-test-markers -->
+ </g>
+ <!-- nested-transforms test -->
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-07-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-07-t.svg
new file mode 100644
index 0000000000..04501edac9
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-07-t.svg
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ owner="CN" reviewer="OA" desc="tests elementary transforms and transform nesting" status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: coords-trans-07-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test verifies the implementation of transforms. It tests elementary transforms
+ and transform nesting.
+ Note that for layout purposes, this test uses nesting of translation with the elementary transforms.
+ </p>
+ <p>
+ The rendered picture should match the reference image exactly except for variations in the labeling text.
+ </p>
+ <p>
+ The test uses the rect element, the fill color (solid primary colors) and transforms.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-trans-07-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <g xml:id="object_1" transform="rotate(30) translate(200, 100)">
+ <rect x="0" y="0" width="150" height="5" fill="green"/>
+ <rect x="0" y="0" width="5" height="50" fill="red"/>
+ </g>
+ <text x="65" y="185" font-size="20">rotate+translate</text>
+
+ <g xml:id="object_2" transform="translate(200,100) rotate(30)">
+ <rect x="0" y="0" width="150" height="5" fill="blue"/>
+ <rect x="0" y="0" width="5" height="50" fill="red"/>
+ </g>
+ <text x="150" y="100" font-size="20">translate+rotate</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-08-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-08-t.svg
new file mode 100644
index 0000000000..23db6cd24f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-08-t.svg
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ owner="CN" reviewer="OA" desc="tests elementary transforms and transform nesting" status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: coords-trans-08-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test verifies the implementation of transforms. It tests elementary transforms
+ and transform nesting.
+ Note that for layout purposes, this test uses nesting of translation with the elementary transforms.
+ </p>
+ <p>
+ The rendered picture should match the reference image exactly except for variations in the labeling text.
+ </p>
+ <p>
+ This test will check if the transfomations performed are carried out in the proper order. The result should differ depending on which transformation comes first.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-trans-08-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g xml:id="object_1" transform="skewX(45) skewY(45)">
+ <rect x="0" y="0" width="150" height="5" fill="blue"/>
+ <rect x="0" y="0" width="5" height="50" fill="red"/>
+ <rect x="150" y="0" width="5" height="50" fill="black"/>
+ <rect x="0" y="50" width="150" height="5" fill="black"/>
+ <ellipse rx="40" ry="15" cx="75" cy="25" fill="purple"/>
+ </g>
+ <text x="30" y="16" font-size="12">skewX(45)+skewY(45)</text>
+
+ <g xml:id="object_2" transform="translate(200,0) skewY(45) skewX(45)">
+ <rect x="0" y="0" width="150" height="5" fill="blue"/>
+ <rect x="0" y="0" width="5" height="50" fill="red"/>
+ <rect x="150" y="0" width="5" height="50" fill="black"/>
+ <rect x="0" y="50" width="150" height="5" fill="black"/>
+ <ellipse rx="40" ry="15" cx="75" cy="25" fill="purple"/>
+ </g>
+ <text x="230" y="16" font-size="12">skewY(45)+skewX(45)</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-09-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-09-t.svg
new file mode 100644
index 0000000000..48e4774c98
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-trans-09-t.svg
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ owner="CN" reviewer="OA" desc="Tests elementary transforms and transform nesting" status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: coords-trans-09-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test verifies the implementation of transforms. It tests elementary transforms
+ and transform nesting.
+ Note that for layout purposes, this test uses nesting of translation with the elementary transforms.
+ </p>
+ <p>
+ The rendered picture should match the reference image exactly except for variations in the labeling text.
+ </p>
+ <p>
+ This test will check if the various matrix operations work
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-trans-09-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <g transform="matrix(0 0 0 0 0 0)">
+ <rect x="0" y="0" width="150" height="5" fill="blue"/>
+ <rect x="0" y="0" width="5" height="50" fill="red"/>
+ </g>
+ <text x="6" y="20" font-size="20">matrix(0 0 0 0 0 0)</text>
+
+ <g transform="matrix(1 0 0 1 100 100)">
+ <rect x="0" y="0" width="150" height="5" fill="blue"/>
+ <rect x="0" y="0" width="5" height="50" fill="red"/>
+ </g>
+ <text x="100" y="100" font-size="20">matrix(1 0 0 1 100 100)</text>
+
+ <g transform="matrix(1.5 0 0 1.5 70 60)">
+ <rect x="0" y="0" width="150" height="5" fill="blue"/>
+ <rect x="0" y="0" width="5" height="50" fill="red"/>
+ </g>
+ <text x="70" y="60" font-size="20">matrix(1.5 0 0 1.5 70 60)</text>
+
+ <g transform="matrix(1 0 0.5 1 30 170)">
+ <rect x="0" y="0" width="150" height="5" fill="blue"/>
+ <rect x="0" y="0" width="5" height="50" fill="red"/>
+ </g>
+ <text x="30" y="170" font-size="20">matrix(1 0 0.5 1 30 170)</text>
+
+ <g transform="matrix(1 0.5 0 1 100 200)">
+ <rect x="0" y="0" width="150" height="5" fill="blue"/>
+ <rect x="0" y="0" width="5" height="50" fill="red"/>
+ </g>
+ <text x="100" y="200" font-size="20">matrix(1 0.5 0 1 100 200)</text>
+
+ <g transform="matrix(0 1 -1 0 450 0)">
+ <rect x="0" y="0" width="150" height="5" fill="blue"/>
+ <rect x="0" y="0" width="5" height="50" fill="red"/>
+ </g>
+ <text x="275" y="30" font-size="20">matrix(0 1 -1 0 450 0)</text>
+
+ <g transform="matrix(1 0.8 0.8 1 300 220)">
+ <rect x="0" y="0" width="150" height="5" fill="blue"/>
+ <rect x="0" y="0" width="5" height="50" fill="red"/>
+ </g>
+ <text x="230" y="220" font-size="20">matrix(1 0.8 0.8 1 300 220)</text>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-units-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-units-01-t.svg
new file mode 100644
index 0000000000..a846fb0d08
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-units-01-t.svg
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="VH" desc="This test validates the processing rules for converting coordinates and length defined in fractions of the current object's bounding box to user space coordinates and length. Note that this test assumes that linear and radial gradients are implemented." status="accepted"
+ approved="yes"
+ version="$Revision: 1.10 $" testname="$RCSfile: coords-units-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Verify the conversion processing of percentage and fraction values relative to object bounding boxes.
+ This is used when defining linear and radial gradients.
+ </p>
+ <p>
+ The test validates conversion for coordinates, width, height and length. The first test defines two
+ corresponding linear gradients, which specify coordinates using fractions for the first and user
+ coordinates for the second. The second test defines two corresponding radial gradients, which specify
+ a length (radius) using fractions for the first and user space for the second.
+ </p>
+ <p>
+ The rendered image should match the reference image.
+ </p>
+ <p>
+ The test also assumes that linear and radial gradients are implemented.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-units-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g font-size="14">
+ <!-- ==================================================================== -->
+ <!-- The following gradients will be used to fill a rectangle with the -->
+ <!-- following geometry in User space: x=0, y=0, width=50 height=20 -->
+ <!-- The gradient vector, in linearBoundingBoxFraction, is defined as: -->
+ <!-- (0, 0) to (1, 0). -->
+ <!-- According to the spec, for our rectangle, this corresponds to the -->
+ <!-- following user space coordinates: -->
+ <!-- (0, 0) becomes (0, 0) and (1, 0) becomes (50, 0) -->
+ <!-- These values are used to define the linearUserSpace gradient. -->
+ <!-- If the test succeeds, all the gradient should fill the rectangles -->
+ <!-- the same way -->
+ <!-- ==================================================================== -->
+ <linearGradient xml:id="linearBoundingBoxFraction" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="0">
+ <stop stop-color="red" offset="0" />
+ <stop stop-color="blue" offset="1" />
+ </linearGradient>
+ <linearGradient xml:id="linearUserSpace" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="50" y2="0">
+ <stop stop-color="red" offset="0" />
+ <stop stop-color="blue" offset="1" />
+ </linearGradient>
+ <!-- Draw Text Comment -->
+ <text x="30" y="30">Bounding box relative coordinates</text>
+ <g transform="translate(30, 40)">
+ <rect x="0" y="0" width="50" height="20" transform="translate(0, 20)" fill="url(#linearBoundingBoxFraction)" />
+ <rect x="0" y="0" width="50" height="20" transform="translate(0, 40)" fill="url(#linearUserSpace)" />
+ <line x1="0" y1="20" x2="50" y2="20" stroke="#cccccc" stroke-width="1" />
+ <line x1="0" y1="40" x2="50" y2="40" stroke="#cccccc" stroke-width="1" />
+ <text x="60" y="35">Fraction</text>
+ <text x="60" y="55">User Space</text>
+ </g>
+ <!-- ==================================================================== -->
+ <!-- The following gradients will be used to fill a rectangle with the -->
+ <!-- following geometry in User space: x=0, y=0, width=60 height=60 -->
+ <!-- The radial gradient in radialBoundingBoxFraction is -->
+ <!-- defined as: cx=0.25 cy=0.25 and r=0.25 -->
+ <!-- These two definition, for our rectangle, should be identical to the -->
+ <!-- following radial gradient in radialUserSpace: -->
+ <!-- cx=15 cy=15 r=15 -->
+ <!-- ==================================================================== -->
+ <radialGradient xml:id="radialBoundingBoxFraction" gradientUnits="objectBoundingBox" cx="0.25" cy="0.25" r="0.25">
+ <stop stop-color="red" offset="0" />
+ <stop stop-color="blue" offset="1" />
+ </radialGradient>
+ <radialGradient xml:id="radialUserSpace" gradientUnits="userSpaceOnUse" cx="15" cy="15" r="15">
+ <stop stop-color="red" offset="0" />
+ <stop stop-color="blue" offset="1" />
+ </radialGradient>
+ <!-- Draw Text Comment -->
+ <text x="30" y="130">Bounding box relative length (percentage and fraction)</text>
+ <g transform="translate(30, 140)">
+ <rect x="0" y="0" width="60" height="60" transform="translate(61, 0)" fill="url(#radialBoundingBoxFraction)" />
+ <rect x="0" y="0" width="60" height="60" transform="translate(122, 0)" fill="url(#radialUserSpace)" />
+ <text x="61" y="73">Fraction</text>
+ <text x="122" y="73">User Space</text>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-viewattr-05-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-viewattr-05-t.svg
new file mode 100644
index 0000000000..d63c231164
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/coords-viewattr-05-t.svg
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg [
+ <!ENTITY Viewport1 "<rect x='.5' y='.5' width='49' height='29' fill='none' stroke='blue' />">
+ <!ENTITY Viewport2 "<rect x='.5' y='.5' width='29' height='59' fill='none' stroke='blue' />">
+]>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="VH" desc="Validates viewBox specification and the preserveAspectRatio attribute" status="accepted"
+ approved="yes"
+ version="$Revision: 1.12 $" testname="$RCSfile: coords-viewattr-05-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test verifies the implementation of the preserveAspectRatio attribute on &lt;image&gt; referencing raster content.
+ This is a modified version of the sample file included in the SVG specification. It exercises the various preserveAspectRatio
+ values and uses a general entity definition in order to make reading of the SVG source easier.
+ </p>
+ <p>The rendered picture should match the reference image exactly except for variations in the labeling text.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: coords-viewattr-05-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g font-size="9" transform="translate(0, 30)">
+ <desc>Example PreserveAspectRatio - demonstrate available options</desc>
+ <text text-anchor="middle" x="240" font-size="16">Test options of preserveAspectRatio on an image element</text>
+ <text x="40" y="30" text-anchor="middle">Raster to fit</text>
+ <g transform="translate(20,40)">
+ <image xlink:href="data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAHgAA/+4ADkFkb2JlAGTAAAAAAf/b AIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBA QEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUw MDU1QEA/QEBAQEBAQEBAQEBA/8AAEQgAZABkAwEiAAIRAQMRAf/EAT8AAAEFAQEBAQEBAAAAAAAA AAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUD DDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1Rk RcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX 5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MV Y3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpam tsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A8/SSR8LCyc/JZi4rDZdYYa0flPgAgSACSaA1 JKkLWuc4NaC5x0AGpJXT9J+onUcwC3Od9jpOoYRutI/q/m/P7l1X1f8Aqth9HYLXgX5xHuuI0b5V g8fHlbixOa+LSsw5fQf5w7/QMscfdxcL6n9BwwP1cXvH5953/wDR+j+C1qsbHoEU1MqHgxob+RES WVPNlyG5zlP+8bXgAbBRAIgiR4Knk9G6TlgjIw6Xz32AO/zhBVxJNjOUTcZGJ8DSnk+pf4v8C4F/ T7XY1nZj/fX/AOSH4rjOq9E6l0mzZmVFrSYZa33Vu+Dv4L19Qvx6Mmp1GRW22p4hzHCQQtDl/imf GQMh96Hj830P8VpgDto+KJLqPrR9UX9M3ZuCDZgzL2cupn8rfP71y63sObHmgJ4zYP2g9ixEEGip JJJSoXa1znBrQS5xgAckleo/Vb6vM6Phh9oBzrwDc790cisfDv5rlfqJ0kZnUXZ1rZpw4LJ4Nrvo /wCbz9y9GWH8W5o8X3eB0GuTz6Blxx6qSSVDrPWcTo2J9pyZcXHbVU36T3eA/iVkwhKchCAMpS0A C9vpLiKP8YxNwGRhbaCdSx8vA+BABXZ42TTl49eTjuD6bWhzHDuCpc/K5sFe7DhEtjdj8FCQOyRJ Vuo9Qxum4lmZlO21V+GpcTw1o8SuQP8AjHd62mCPQn/Se+P82EsHKZ8wMsUOIR62Br9UGQG73CSq 9M6li9Uw2ZmK6a36EHRzXDlrh4hWlDKJjIxkKMTRBXLOa17Sx4DmuBDmnUEHsV5j9bfq/wDsfMFt AP2LIJNX8h3ev+5enqj1rplfVem3Yb43PE1OP5tjdWlWuR5o8vlBJ9E9Jjw7/RbKNh8fSRPQu9f7 PtPrb/T2d987dv3pLqLHfx+jA+ofU/CGH0HHkQ+8G9/9v6P/AEYW0h41Qox6qRxUxrB/ZEIi4/NM 5Ms5n9ORl9rYAoAKXEf4xqLicLIAJoaHsJ7B5gj7wF26Hk42Pl0ux8mtttLxDmOEgqTlc/sZoZa4 hG7HgdFSFinxVeo/Uui+n6v44ukby97Gnsxxlv38p6PqX9X6b/WGOXwZax7i5g/snn5rcAAAAEAc BXfiHxDHnxxx44yri4iZfkFkIEGy8v8A4waL7Oj1WVgmum4OtA7Atc0OPzK85XttlbLWOrsaHseC HNcJBB7ELCP1K+rxv9b7O6Jn0t7tn3TP4o8h8Rx4MXt5Iy0JMTHx7qlAk2Gl/i8ovr6ZkWvBFVtv 6Ke+0Q5w/J8l1ajVVXTW2qpoZWwQ1jRAAHYBSWfzGb3s08tcPGbpeBQpSSSSiS8d+xGf8/PU2/od n22I03fQ/wDPmqS6z7Oz7V9pj3+n6c+W7ckrv36fc/7m9j+1bw/9K0oIIBHB4SVPo2SMvpOHkAzv pZP9YCHfiFcVOcTGUoneJI+xKkkkkEqSSSSUpJJJJSkkkklKSSSSUrySWX+0m/8AOT9mz/2l9T+3 v4/zUlL7E+3+T93/AAUX+dOP/i+6kLsC3p7z+kxnb2D/AIN+v4O/KusXkHROq2dJ6lVmMktadtrB +dW76Q/u8165j305NFeRQ4PqtaHMcO4KufFOXOPOcgHoza/4XUftWwNiuzMkASeFiYv1u6Nk59mC LdjmO212v0rtPfa74+PK2yARB1BXKdc+ouLmOdkdNcMa86uqP804+UfR/Iq3LR5eRlHPKUOIeiQ2 B8Uyvo9WkvNmZv1u+rf6O1rzjt0AsHq0/wBl44+RWjj/AOMd4AGTggnu6uyP+i5p/Kp5fDM/zYjD PDpKEh+1HGOuj3CS41/+MfFA9mFYXeBeAPwBWfk/XzrOWfSwMdlLnaDaDbZ8u34IR+Gc2d4CA7yk K/BXHF7nP6jhdOoORmWtqrHE8uPg0ckqt0Tr2F1ql9mNLH1uh9T43Afmu07FcbifVP6wdavGT1Wx 1LDy+47rI8G19vnC7bpPRsDpFHo4dcE/zlrtXvP8pyGfDy2HGYjJ72e94fJHwSDInag3kznNY0uc Ya0SSeAAnXLfXnrgw8L9m0O/WcofpI5ZV3/zuPvVfBhlmyxxx/SO/YdSkmhbyv7fd/zp/bEn0/W4 /wCB/m4/zEliJLqfu2L93/Jez/gdmCz+NqXUfVH60fsx4wc1x+w2H2POvouPf+qe/wB65dJHNhhm xnHMWD9oPcKBINh9ta5r2h7CHNcJa4agg9wnXmH1f+tuZ0iKLQcjC/0RPuZ/xZ/gvQemda6b1Wvf h3B7vzqj7bG/FpXN81yOXlySRxw6TG317M0ZAt7nQqnf0bpORrdhUvJ7mts/eBKuJKrGUom4kx8j SXNZ9W+gsMjApnzbP5VeoxcbHEY9LKR4VtDf+pCIknSy5JfNOUv7xJVQUkmc5rGlzyGtGpJMABcv 1z684WG11HTYysnj1P8ABMPx/O+X3p2HBlzS4ccTL8h5lRIG7qdf6/i9FxfUsIfkvB9CidXHxPg0 LyzMzMjOybMrJdvutO5zv4DyCWZmZOdkOycqw23P+k535B4BBXR8lyUeWj+9kl80v2DwYZSvyUkk kri1SSSSSlIlHr+q37Pv9afZ6c758tuqSSB2P7dlPc9E/wCfm1vqbPR0j7b9KP7H6T711mP9q2D7 V6e/v6e6P+kkkuZ575z/ALm3/wAh+1nj9fql+Cy+p/8AOTaf2b9l/wCub9/y/NSSVfB84/m/+q/K k/X6PA9f/wCdO4/tj1vTnT/Q/L0/YsNJJdTy381H+a/6j8n0YDv1+qkkklMhSSSSSn//2Q==" width="40" height="40" preserveAspectRatio="none" />
+ </g>
+ <text x="35.5" y="110" text-anchor="middle">Viewport 1</text>
+ <g transform="translate(10,120)">&Viewport1;</g>
+ <text x="35.5" y="180" text-anchor="middle">Viewport 2</text>
+ <g transform="translate(20,190)">&Viewport2;</g>
+ <g xml:id="meet-group-1" transform="translate(120, 50)">
+ <text x="0" y="-20">---------- meet --------------------</text>
+ <g>
+ <text y="-5">xMin*</text>&Viewport1;
+ <image xlink:href="data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAHgAA/+4ADkFkb2JlAGTAAAAAAf/b AIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBA QEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUw MDU1QEA/QEBAQEBAQEBAQEBA/8AAEQgAZABkAwEiAAIRAQMRAf/EAT8AAAEFAQEBAQEBAAAAAAAA AAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUD DDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1Rk RcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX 5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MV Y3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpam tsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A8/SSR8LCyc/JZi4rDZdYYa0flPgAgSACSaA1 JKkLWuc4NaC5x0AGpJXT9J+onUcwC3Od9jpOoYRutI/q/m/P7l1X1f8Aqth9HYLXgX5xHuuI0b5V g8fHlbixOa+LSsw5fQf5w7/QMscfdxcL6n9BwwP1cXvH5953/wDR+j+C1qsbHoEU1MqHgxob+RES WVPNlyG5zlP+8bXgAbBRAIgiR4Knk9G6TlgjIw6Xz32AO/zhBVxJNjOUTcZGJ8DSnk+pf4v8C4F/ T7XY1nZj/fX/AOSH4rjOq9E6l0mzZmVFrSYZa33Vu+Dv4L19Qvx6Mmp1GRW22p4hzHCQQtDl/imf GQMh96Hj830P8VpgDto+KJLqPrR9UX9M3ZuCDZgzL2cupn8rfP71y63sObHmgJ4zYP2g9ixEEGip JJJSoXa1znBrQS5xgAckleo/Vb6vM6Phh9oBzrwDc790cisfDv5rlfqJ0kZnUXZ1rZpw4LJ4Nrvo /wCbz9y9GWH8W5o8X3eB0GuTz6Blxx6qSSVDrPWcTo2J9pyZcXHbVU36T3eA/iVkwhKchCAMpS0A C9vpLiKP8YxNwGRhbaCdSx8vA+BABXZ42TTl49eTjuD6bWhzHDuCpc/K5sFe7DhEtjdj8FCQOyRJ Vuo9Qxum4lmZlO21V+GpcTw1o8SuQP8AjHd62mCPQn/Se+P82EsHKZ8wMsUOIR62Br9UGQG73CSq 9M6li9Uw2ZmK6a36EHRzXDlrh4hWlDKJjIxkKMTRBXLOa17Sx4DmuBDmnUEHsV5j9bfq/wDsfMFt AP2LIJNX8h3ev+5enqj1rplfVem3Yb43PE1OP5tjdWlWuR5o8vlBJ9E9Jjw7/RbKNh8fSRPQu9f7 PtPrb/T2d987dv3pLqLHfx+jA+ofU/CGH0HHkQ+8G9/9v6P/AEYW0h41Qox6qRxUxrB/ZEIi4/NM 5Ms5n9ORl9rYAoAKXEf4xqLicLIAJoaHsJ7B5gj7wF26Hk42Pl0ux8mtttLxDmOEgqTlc/sZoZa4 hG7HgdFSFinxVeo/Uui+n6v44ukby97Gnsxxlv38p6PqX9X6b/WGOXwZax7i5g/snn5rcAAAAEAc BXfiHxDHnxxx44yri4iZfkFkIEGy8v8A4waL7Oj1WVgmum4OtA7Atc0OPzK85XttlbLWOrsaHseC HNcJBB7ELCP1K+rxv9b7O6Jn0t7tn3TP4o8h8Rx4MXt5Iy0JMTHx7qlAk2Gl/i8ovr6ZkWvBFVtv 6Ke+0Q5w/J8l1ajVVXTW2qpoZWwQ1jRAAHYBSWfzGb3s08tcPGbpeBQpSSSSiS8d+xGf8/PU2/od n22I03fQ/wDPmqS6z7Oz7V9pj3+n6c+W7ckrv36fc/7m9j+1bw/9K0oIIBHB4SVPo2SMvpOHkAzv pZP9YCHfiFcVOcTGUoneJI+xKkkkkEqSSSSUpJJJJSkkkklKSSSSUrySWX+0m/8AOT9mz/2l9T+3 v4/zUlL7E+3+T93/AAUX+dOP/i+6kLsC3p7z+kxnb2D/AIN+v4O/KusXkHROq2dJ6lVmMktadtrB +dW76Q/u8165j305NFeRQ4PqtaHMcO4KufFOXOPOcgHoza/4XUftWwNiuzMkASeFiYv1u6Nk59mC LdjmO212v0rtPfa74+PK2yARB1BXKdc+ouLmOdkdNcMa86uqP804+UfR/Iq3LR5eRlHPKUOIeiQ2 B8Uyvo9WkvNmZv1u+rf6O1rzjt0AsHq0/wBl44+RWjj/AOMd4AGTggnu6uyP+i5p/Kp5fDM/zYjD PDpKEh+1HGOuj3CS41/+MfFA9mFYXeBeAPwBWfk/XzrOWfSwMdlLnaDaDbZ8u34IR+Gc2d4CA7yk K/BXHF7nP6jhdOoORmWtqrHE8uPg0ckqt0Tr2F1ql9mNLH1uh9T43Afmu07FcbifVP6wdavGT1Wx 1LDy+47rI8G19vnC7bpPRsDpFHo4dcE/zlrtXvP8pyGfDy2HGYjJ72e94fJHwSDInag3kznNY0uc Ya0SSeAAnXLfXnrgw8L9m0O/WcofpI5ZV3/zuPvVfBhlmyxxx/SO/YdSkmhbyv7fd/zp/bEn0/W4 /wCB/m4/zEliJLqfu2L93/Jez/gdmCz+NqXUfVH60fsx4wc1x+w2H2POvouPf+qe/wB65dJHNhhm xnHMWD9oPcKBINh9ta5r2h7CHNcJa4agg9wnXmH1f+tuZ0iKLQcjC/0RPuZ/xZ/gvQemda6b1Wvf h3B7vzqj7bG/FpXN81yOXlySRxw6TG317M0ZAt7nQqnf0bpORrdhUvJ7mts/eBKuJKrGUom4kx8j SXNZ9W+gsMjApnzbP5VeoxcbHEY9LKR4VtDf+pCIknSy5JfNOUv7xJVQUkmc5rGlzyGtGpJMABcv 1z684WG11HTYysnj1P8ABMPx/O+X3p2HBlzS4ccTL8h5lRIG7qdf6/i9FxfUsIfkvB9CidXHxPg0 LyzMzMjOybMrJdvutO5zv4DyCWZmZOdkOycqw23P+k535B4BBXR8lyUeWj+9kl80v2DwYZSvyUkk kri1SSSSSlIlHr+q37Pv9afZ6c758tuqSSB2P7dlPc9E/wCfm1vqbPR0j7b9KP7H6T711mP9q2D7 V6e/v6e6P+kkkuZ575z/ALm3/wAh+1nj9fql+Cy+p/8AOTaf2b9l/wCub9/y/NSSVfB84/m/+q/K k/X6PA9f/wCdO4/tj1vTnT/Q/L0/YsNJJdTy381H+a/6j8n0YDv1+qkkklMhSSSSSn//2Q==" preserveAspectRatio="xMinYMin meet" width="50" height="30" />
+ </g>
+ <g transform="translate(70,0)">
+ <text y="-5">xMid*</text>&Viewport1;
+ <image xlink:href="data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAHgAA/+4ADkFkb2JlAGTAAAAAAf/b AIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBA QEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUw MDU1QEA/QEBAQEBAQEBAQEBA/8AAEQgAZABkAwEiAAIRAQMRAf/EAT8AAAEFAQEBAQEBAAAAAAAA AAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUD DDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1Rk RcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX 5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MV Y3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpam tsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A8/SSR8LCyc/JZi4rDZdYYa0flPgAgSACSaA1 JKkLWuc4NaC5x0AGpJXT9J+onUcwC3Od9jpOoYRutI/q/m/P7l1X1f8Aqth9HYLXgX5xHuuI0b5V g8fHlbixOa+LSsw5fQf5w7/QMscfdxcL6n9BwwP1cXvH5953/wDR+j+C1qsbHoEU1MqHgxob+RES WVPNlyG5zlP+8bXgAbBRAIgiR4Knk9G6TlgjIw6Xz32AO/zhBVxJNjOUTcZGJ8DSnk+pf4v8C4F/ T7XY1nZj/fX/AOSH4rjOq9E6l0mzZmVFrSYZa33Vu+Dv4L19Qvx6Mmp1GRW22p4hzHCQQtDl/imf GQMh96Hj830P8VpgDto+KJLqPrR9UX9M3ZuCDZgzL2cupn8rfP71y63sObHmgJ4zYP2g9ixEEGip JJJSoXa1znBrQS5xgAckleo/Vb6vM6Phh9oBzrwDc790cisfDv5rlfqJ0kZnUXZ1rZpw4LJ4Nrvo /wCbz9y9GWH8W5o8X3eB0GuTz6Blxx6qSSVDrPWcTo2J9pyZcXHbVU36T3eA/iVkwhKchCAMpS0A C9vpLiKP8YxNwGRhbaCdSx8vA+BABXZ42TTl49eTjuD6bWhzHDuCpc/K5sFe7DhEtjdj8FCQOyRJ Vuo9Qxum4lmZlO21V+GpcTw1o8SuQP8AjHd62mCPQn/Se+P82EsHKZ8wMsUOIR62Br9UGQG73CSq 9M6li9Uw2ZmK6a36EHRzXDlrh4hWlDKJjIxkKMTRBXLOa17Sx4DmuBDmnUEHsV5j9bfq/wDsfMFt AP2LIJNX8h3ev+5enqj1rplfVem3Yb43PE1OP5tjdWlWuR5o8vlBJ9E9Jjw7/RbKNh8fSRPQu9f7 PtPrb/T2d987dv3pLqLHfx+jA+ofU/CGH0HHkQ+8G9/9v6P/AEYW0h41Qox6qRxUxrB/ZEIi4/NM 5Ms5n9ORl9rYAoAKXEf4xqLicLIAJoaHsJ7B5gj7wF26Hk42Pl0ux8mtttLxDmOEgqTlc/sZoZa4 hG7HgdFSFinxVeo/Uui+n6v44ukby97Gnsxxlv38p6PqX9X6b/WGOXwZax7i5g/snn5rcAAAAEAc BXfiHxDHnxxx44yri4iZfkFkIEGy8v8A4waL7Oj1WVgmum4OtA7Atc0OPzK85XttlbLWOrsaHseC HNcJBB7ELCP1K+rxv9b7O6Jn0t7tn3TP4o8h8Rx4MXt5Iy0JMTHx7qlAk2Gl/i8ovr6ZkWvBFVtv 6Ke+0Q5w/J8l1ajVVXTW2qpoZWwQ1jRAAHYBSWfzGb3s08tcPGbpeBQpSSSSiS8d+xGf8/PU2/od n22I03fQ/wDPmqS6z7Oz7V9pj3+n6c+W7ckrv36fc/7m9j+1bw/9K0oIIBHB4SVPo2SMvpOHkAzv pZP9YCHfiFcVOcTGUoneJI+xKkkkkEqSSSSUpJJJJSkkkklKSSSSUrySWX+0m/8AOT9mz/2l9T+3 v4/zUlL7E+3+T93/AAUX+dOP/i+6kLsC3p7z+kxnb2D/AIN+v4O/KusXkHROq2dJ6lVmMktadtrB +dW76Q/u8165j305NFeRQ4PqtaHMcO4KufFOXOPOcgHoza/4XUftWwNiuzMkASeFiYv1u6Nk59mC LdjmO212v0rtPfa74+PK2yARB1BXKdc+ouLmOdkdNcMa86uqP804+UfR/Iq3LR5eRlHPKUOIeiQ2 B8Uyvo9WkvNmZv1u+rf6O1rzjt0AsHq0/wBl44+RWjj/AOMd4AGTggnu6uyP+i5p/Kp5fDM/zYjD PDpKEh+1HGOuj3CS41/+MfFA9mFYXeBeAPwBWfk/XzrOWfSwMdlLnaDaDbZ8u34IR+Gc2d4CA7yk K/BXHF7nP6jhdOoORmWtqrHE8uPg0ckqt0Tr2F1ql9mNLH1uh9T43Afmu07FcbifVP6wdavGT1Wx 1LDy+47rI8G19vnC7bpPRsDpFHo4dcE/zlrtXvP8pyGfDy2HGYjJ72e94fJHwSDInag3kznNY0uc Ya0SSeAAnXLfXnrgw8L9m0O/WcofpI5ZV3/zuPvVfBhlmyxxx/SO/YdSkmhbyv7fd/zp/bEn0/W4 /wCB/m4/zEliJLqfu2L93/Jez/gdmCz+NqXUfVH60fsx4wc1x+w2H2POvouPf+qe/wB65dJHNhhm xnHMWD9oPcKBINh9ta5r2h7CHNcJa4agg9wnXmH1f+tuZ0iKLQcjC/0RPuZ/xZ/gvQemda6b1Wvf h3B7vzqj7bG/FpXN81yOXlySRxw6TG317M0ZAt7nQqnf0bpORrdhUvJ7mts/eBKuJKrGUom4kx8j SXNZ9W+gsMjApnzbP5VeoxcbHEY9LKR4VtDf+pCIknSy5JfNOUv7xJVQUkmc5rGlzyGtGpJMABcv 1z684WG11HTYysnj1P8ABMPx/O+X3p2HBlzS4ccTL8h5lRIG7qdf6/i9FxfUsIfkvB9CidXHxPg0 LyzMzMjOybMrJdvutO5zv4DyCWZmZOdkOycqw23P+k535B4BBXR8lyUeWj+9kl80v2DwYZSvyUkk kri1SSSSSlIlHr+q37Pv9afZ6c758tuqSSB2P7dlPc9E/wCfm1vqbPR0j7b9KP7H6T711mP9q2D7 V6e/v6e6P+kkkuZ575z/ALm3/wAh+1nj9fql+Cy+p/8AOTaf2b9l/wCub9/y/NSSVfB84/m/+q/K k/X6PA9f/wCdO4/tj1vTnT/Q/L0/YsNJJdTy381H+a/6j8n0YDv1+qkkklMhSSSSSn//2Q==" preserveAspectRatio="xMidYMid meet" width="50" height="30" />
+ </g>
+ <g transform="translate(0,50)">
+ <text y="-5">xMax*</text>&Viewport1;
+ <image xlink:href="data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAHgAA/+4ADkFkb2JlAGTAAAAAAf/b AIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBA QEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUw MDU1QEA/QEBAQEBAQEBAQEBA/8AAEQgAZABkAwEiAAIRAQMRAf/EAT8AAAEFAQEBAQEBAAAAAAAA AAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUD DDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1Rk RcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX 5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MV Y3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpam tsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A8/SSR8LCyc/JZi4rDZdYYa0flPgAgSACSaA1 JKkLWuc4NaC5x0AGpJXT9J+onUcwC3Od9jpOoYRutI/q/m/P7l1X1f8Aqth9HYLXgX5xHuuI0b5V g8fHlbixOa+LSsw5fQf5w7/QMscfdxcL6n9BwwP1cXvH5953/wDR+j+C1qsbHoEU1MqHgxob+RES WVPNlyG5zlP+8bXgAbBRAIgiR4Knk9G6TlgjIw6Xz32AO/zhBVxJNjOUTcZGJ8DSnk+pf4v8C4F/ T7XY1nZj/fX/AOSH4rjOq9E6l0mzZmVFrSYZa33Vu+Dv4L19Qvx6Mmp1GRW22p4hzHCQQtDl/imf GQMh96Hj830P8VpgDto+KJLqPrR9UX9M3ZuCDZgzL2cupn8rfP71y63sObHmgJ4zYP2g9ixEEGip JJJSoXa1znBrQS5xgAckleo/Vb6vM6Phh9oBzrwDc790cisfDv5rlfqJ0kZnUXZ1rZpw4LJ4Nrvo /wCbz9y9GWH8W5o8X3eB0GuTz6Blxx6qSSVDrPWcTo2J9pyZcXHbVU36T3eA/iVkwhKchCAMpS0A C9vpLiKP8YxNwGRhbaCdSx8vA+BABXZ42TTl49eTjuD6bWhzHDuCpc/K5sFe7DhEtjdj8FCQOyRJ Vuo9Qxum4lmZlO21V+GpcTw1o8SuQP8AjHd62mCPQn/Se+P82EsHKZ8wMsUOIR62Br9UGQG73CSq 9M6li9Uw2ZmK6a36EHRzXDlrh4hWlDKJjIxkKMTRBXLOa17Sx4DmuBDmnUEHsV5j9bfq/wDsfMFt AP2LIJNX8h3ev+5enqj1rplfVem3Yb43PE1OP5tjdWlWuR5o8vlBJ9E9Jjw7/RbKNh8fSRPQu9f7 PtPrb/T2d987dv3pLqLHfx+jA+ofU/CGH0HHkQ+8G9/9v6P/AEYW0h41Qox6qRxUxrB/ZEIi4/NM 5Ms5n9ORl9rYAoAKXEf4xqLicLIAJoaHsJ7B5gj7wF26Hk42Pl0ux8mtttLxDmOEgqTlc/sZoZa4 hG7HgdFSFinxVeo/Uui+n6v44ukby97Gnsxxlv38p6PqX9X6b/WGOXwZax7i5g/snn5rcAAAAEAc BXfiHxDHnxxx44yri4iZfkFkIEGy8v8A4waL7Oj1WVgmum4OtA7Atc0OPzK85XttlbLWOrsaHseC HNcJBB7ELCP1K+rxv9b7O6Jn0t7tn3TP4o8h8Rx4MXt5Iy0JMTHx7qlAk2Gl/i8ovr6ZkWvBFVtv 6Ke+0Q5w/J8l1ajVVXTW2qpoZWwQ1jRAAHYBSWfzGb3s08tcPGbpeBQpSSSSiS8d+xGf8/PU2/od n22I03fQ/wDPmqS6z7Oz7V9pj3+n6c+W7ckrv36fc/7m9j+1bw/9K0oIIBHB4SVPo2SMvpOHkAzv pZP9YCHfiFcVOcTGUoneJI+xKkkkkEqSSSSUpJJJJSkkkklKSSSSUrySWX+0m/8AOT9mz/2l9T+3 v4/zUlL7E+3+T93/AAUX+dOP/i+6kLsC3p7z+kxnb2D/AIN+v4O/KusXkHROq2dJ6lVmMktadtrB +dW76Q/u8165j305NFeRQ4PqtaHMcO4KufFOXOPOcgHoza/4XUftWwNiuzMkASeFiYv1u6Nk59mC LdjmO212v0rtPfa74+PK2yARB1BXKdc+ouLmOdkdNcMa86uqP804+UfR/Iq3LR5eRlHPKUOIeiQ2 B8Uyvo9WkvNmZv1u+rf6O1rzjt0AsHq0/wBl44+RWjj/AOMd4AGTggnu6uyP+i5p/Kp5fDM/zYjD PDpKEh+1HGOuj3CS41/+MfFA9mFYXeBeAPwBWfk/XzrOWfSwMdlLnaDaDbZ8u34IR+Gc2d4CA7yk K/BXHF7nP6jhdOoORmWtqrHE8uPg0ckqt0Tr2F1ql9mNLH1uh9T43Afmu07FcbifVP6wdavGT1Wx 1LDy+47rI8G19vnC7bpPRsDpFHo4dcE/zlrtXvP8pyGfDy2HGYjJ72e94fJHwSDInag3kznNY0uc Ya0SSeAAnXLfXnrgw8L9m0O/WcofpI5ZV3/zuPvVfBhlmyxxx/SO/YdSkmhbyv7fd/zp/bEn0/W4 /wCB/m4/zEliJLqfu2L93/Jez/gdmCz+NqXUfVH60fsx4wc1x+w2H2POvouPf+qe/wB65dJHNhhm xnHMWD9oPcKBINh9ta5r2h7CHNcJa4agg9wnXmH1f+tuZ0iKLQcjC/0RPuZ/xZ/gvQemda6b1Wvf h3B7vzqj7bG/FpXN81yOXlySRxw6TG317M0ZAt7nQqnf0bpORrdhUvJ7mts/eBKuJKrGUom4kx8j SXNZ9W+gsMjApnzbP5VeoxcbHEY9LKR4VtDf+pCIknSy5JfNOUv7xJVQUkmc5rGlzyGtGpJMABcv 1z684WG11HTYysnj1P8ABMPx/O+X3p2HBlzS4ccTL8h5lRIG7qdf6/i9FxfUsIfkvB9CidXHxPg0 LyzMzMjOybMrJdvutO5zv4DyCWZmZOdkOycqw23P+k535B4BBXR8lyUeWj+9kl80v2DwYZSvyUkk kri1SSSSSlIlHr+q37Pv9afZ6c758tuqSSB2P7dlPc9E/wCfm1vqbPR0j7b9KP7H6T711mP9q2D7 V6e/v6e6P+kkkuZ575z/ALm3/wAh+1nj9fql+Cy+p/8AOTaf2b9l/wCub9/y/NSSVfB84/m/+q/K k/X6PA9f/wCdO4/tj1vTnT/Q/L0/YsNJJdTy381H+a/6j8n0YDv1+qkkklMhSSSSSn//2Q==" preserveAspectRatio="xMaxYMax meet" width="50" height="30" />
+ </g>
+ </g>
+ <g xml:id="meet-group-2" transform="translate(300, 50)">
+ <text x="0" y="-20">---------- meet ------------------------</text>
+ <g>
+ <text y="-5">*YMin</text>&Viewport2;
+ <image xlink:href="data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAHgAA/+4ADkFkb2JlAGTAAAAAAf/b AIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBA QEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUw MDU1QEA/QEBAQEBAQEBAQEBA/8AAEQgAZABkAwEiAAIRAQMRAf/EAT8AAAEFAQEBAQEBAAAAAAAA AAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUD DDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1Rk RcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX 5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MV Y3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpam tsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A8/SSR8LCyc/JZi4rDZdYYa0flPgAgSACSaA1 JKkLWuc4NaC5x0AGpJXT9J+onUcwC3Od9jpOoYRutI/q/m/P7l1X1f8Aqth9HYLXgX5xHuuI0b5V g8fHlbixOa+LSsw5fQf5w7/QMscfdxcL6n9BwwP1cXvH5953/wDR+j+C1qsbHoEU1MqHgxob+RES WVPNlyG5zlP+8bXgAbBRAIgiR4Knk9G6TlgjIw6Xz32AO/zhBVxJNjOUTcZGJ8DSnk+pf4v8C4F/ T7XY1nZj/fX/AOSH4rjOq9E6l0mzZmVFrSYZa33Vu+Dv4L19Qvx6Mmp1GRW22p4hzHCQQtDl/imf GQMh96Hj830P8VpgDto+KJLqPrR9UX9M3ZuCDZgzL2cupn8rfP71y63sObHmgJ4zYP2g9ixEEGip JJJSoXa1znBrQS5xgAckleo/Vb6vM6Phh9oBzrwDc790cisfDv5rlfqJ0kZnUXZ1rZpw4LJ4Nrvo /wCbz9y9GWH8W5o8X3eB0GuTz6Blxx6qSSVDrPWcTo2J9pyZcXHbVU36T3eA/iVkwhKchCAMpS0A C9vpLiKP8YxNwGRhbaCdSx8vA+BABXZ42TTl49eTjuD6bWhzHDuCpc/K5sFe7DhEtjdj8FCQOyRJ Vuo9Qxum4lmZlO21V+GpcTw1o8SuQP8AjHd62mCPQn/Se+P82EsHKZ8wMsUOIR62Br9UGQG73CSq 9M6li9Uw2ZmK6a36EHRzXDlrh4hWlDKJjIxkKMTRBXLOa17Sx4DmuBDmnUEHsV5j9bfq/wDsfMFt AP2LIJNX8h3ev+5enqj1rplfVem3Yb43PE1OP5tjdWlWuR5o8vlBJ9E9Jjw7/RbKNh8fSRPQu9f7 PtPrb/T2d987dv3pLqLHfx+jA+ofU/CGH0HHkQ+8G9/9v6P/AEYW0h41Qox6qRxUxrB/ZEIi4/NM 5Ms5n9ORl9rYAoAKXEf4xqLicLIAJoaHsJ7B5gj7wF26Hk42Pl0ux8mtttLxDmOEgqTlc/sZoZa4 hG7HgdFSFinxVeo/Uui+n6v44ukby97Gnsxxlv38p6PqX9X6b/WGOXwZax7i5g/snn5rcAAAAEAc BXfiHxDHnxxx44yri4iZfkFkIEGy8v8A4waL7Oj1WVgmum4OtA7Atc0OPzK85XttlbLWOrsaHseC HNcJBB7ELCP1K+rxv9b7O6Jn0t7tn3TP4o8h8Rx4MXt5Iy0JMTHx7qlAk2Gl/i8ovr6ZkWvBFVtv 6Ke+0Q5w/J8l1ajVVXTW2qpoZWwQ1jRAAHYBSWfzGb3s08tcPGbpeBQpSSSSiS8d+xGf8/PU2/od n22I03fQ/wDPmqS6z7Oz7V9pj3+n6c+W7ckrv36fc/7m9j+1bw/9K0oIIBHB4SVPo2SMvpOHkAzv pZP9YCHfiFcVOcTGUoneJI+xKkkkkEqSSSSUpJJJJSkkkklKSSSSUrySWX+0m/8AOT9mz/2l9T+3 v4/zUlL7E+3+T93/AAUX+dOP/i+6kLsC3p7z+kxnb2D/AIN+v4O/KusXkHROq2dJ6lVmMktadtrB +dW76Q/u8165j305NFeRQ4PqtaHMcO4KufFOXOPOcgHoza/4XUftWwNiuzMkASeFiYv1u6Nk59mC LdjmO212v0rtPfa74+PK2yARB1BXKdc+ouLmOdkdNcMa86uqP804+UfR/Iq3LR5eRlHPKUOIeiQ2 B8Uyvo9WkvNmZv1u+rf6O1rzjt0AsHq0/wBl44+RWjj/AOMd4AGTggnu6uyP+i5p/Kp5fDM/zYjD PDpKEh+1HGOuj3CS41/+MfFA9mFYXeBeAPwBWfk/XzrOWfSwMdlLnaDaDbZ8u34IR+Gc2d4CA7yk K/BXHF7nP6jhdOoORmWtqrHE8uPg0ckqt0Tr2F1ql9mNLH1uh9T43Afmu07FcbifVP6wdavGT1Wx 1LDy+47rI8G19vnC7bpPRsDpFHo4dcE/zlrtXvP8pyGfDy2HGYjJ72e94fJHwSDInag3kznNY0uc Ya0SSeAAnXLfXnrgw8L9m0O/WcofpI5ZV3/zuPvVfBhlmyxxx/SO/YdSkmhbyv7fd/zp/bEn0/W4 /wCB/m4/zEliJLqfu2L93/Jez/gdmCz+NqXUfVH60fsx4wc1x+w2H2POvouPf+qe/wB65dJHNhhm xnHMWD9oPcKBINh9ta5r2h7CHNcJa4agg9wnXmH1f+tuZ0iKLQcjC/0RPuZ/xZ/gvQemda6b1Wvf h3B7vzqj7bG/FpXN81yOXlySRxw6TG317M0ZAt7nQqnf0bpORrdhUvJ7mts/eBKuJKrGUom4kx8j SXNZ9W+gsMjApnzbP5VeoxcbHEY9LKR4VtDf+pCIknSy5JfNOUv7xJVQUkmc5rGlzyGtGpJMABcv 1z684WG11HTYysnj1P8ABMPx/O+X3p2HBlzS4ccTL8h5lRIG7qdf6/i9FxfUsIfkvB9CidXHxPg0 LyzMzMjOybMrJdvutO5zv4DyCWZmZOdkOycqw23P+k535B4BBXR8lyUeWj+9kl80v2DwYZSvyUkk kri1SSSSSlIlHr+q37Pv9afZ6c758tuqSSB2P7dlPc9E/wCfm1vqbPR0j7b9KP7H6T711mP9q2D7 V6e/v6e6P+kkkuZ575z/ALm3/wAh+1nj9fql+Cy+p/8AOTaf2b9l/wCub9/y/NSSVfB84/m/+q/K k/X6PA9f/wCdO4/tj1vTnT/Q/L0/YsNJJdTy381H+a/6j8n0YDv1+qkkklMhSSSSSn//2Q==" preserveAspectRatio="xMinYMin meet" width="30" height="60" />
+ </g>
+ <g transform="translate(50, 0)">
+ <text y="-5">*YMid</text>&Viewport2;
+ <image xlink:href="data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAHgAA/+4ADkFkb2JlAGTAAAAAAf/b AIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBA QEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUw MDU1QEA/QEBAQEBAQEBAQEBA/8AAEQgAZABkAwEiAAIRAQMRAf/EAT8AAAEFAQEBAQEBAAAAAAAA AAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUD DDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1Rk RcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX 5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MV Y3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpam tsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A8/SSR8LCyc/JZi4rDZdYYa0flPgAgSACSaA1 JKkLWuc4NaC5x0AGpJXT9J+onUcwC3Od9jpOoYRutI/q/m/P7l1X1f8Aqth9HYLXgX5xHuuI0b5V g8fHlbixOa+LSsw5fQf5w7/QMscfdxcL6n9BwwP1cXvH5953/wDR+j+C1qsbHoEU1MqHgxob+RES WVPNlyG5zlP+8bXgAbBRAIgiR4Knk9G6TlgjIw6Xz32AO/zhBVxJNjOUTcZGJ8DSnk+pf4v8C4F/ T7XY1nZj/fX/AOSH4rjOq9E6l0mzZmVFrSYZa33Vu+Dv4L19Qvx6Mmp1GRW22p4hzHCQQtDl/imf GQMh96Hj830P8VpgDto+KJLqPrR9UX9M3ZuCDZgzL2cupn8rfP71y63sObHmgJ4zYP2g9ixEEGip JJJSoXa1znBrQS5xgAckleo/Vb6vM6Phh9oBzrwDc790cisfDv5rlfqJ0kZnUXZ1rZpw4LJ4Nrvo /wCbz9y9GWH8W5o8X3eB0GuTz6Blxx6qSSVDrPWcTo2J9pyZcXHbVU36T3eA/iVkwhKchCAMpS0A C9vpLiKP8YxNwGRhbaCdSx8vA+BABXZ42TTl49eTjuD6bWhzHDuCpc/K5sFe7DhEtjdj8FCQOyRJ Vuo9Qxum4lmZlO21V+GpcTw1o8SuQP8AjHd62mCPQn/Se+P82EsHKZ8wMsUOIR62Br9UGQG73CSq 9M6li9Uw2ZmK6a36EHRzXDlrh4hWlDKJjIxkKMTRBXLOa17Sx4DmuBDmnUEHsV5j9bfq/wDsfMFt AP2LIJNX8h3ev+5enqj1rplfVem3Yb43PE1OP5tjdWlWuR5o8vlBJ9E9Jjw7/RbKNh8fSRPQu9f7 PtPrb/T2d987dv3pLqLHfx+jA+ofU/CGH0HHkQ+8G9/9v6P/AEYW0h41Qox6qRxUxrB/ZEIi4/NM 5Ms5n9ORl9rYAoAKXEf4xqLicLIAJoaHsJ7B5gj7wF26Hk42Pl0ux8mtttLxDmOEgqTlc/sZoZa4 hG7HgdFSFinxVeo/Uui+n6v44ukby97Gnsxxlv38p6PqX9X6b/WGOXwZax7i5g/snn5rcAAAAEAc BXfiHxDHnxxx44yri4iZfkFkIEGy8v8A4waL7Oj1WVgmum4OtA7Atc0OPzK85XttlbLWOrsaHseC HNcJBB7ELCP1K+rxv9b7O6Jn0t7tn3TP4o8h8Rx4MXt5Iy0JMTHx7qlAk2Gl/i8ovr6ZkWvBFVtv 6Ke+0Q5w/J8l1ajVVXTW2qpoZWwQ1jRAAHYBSWfzGb3s08tcPGbpeBQpSSSSiS8d+xGf8/PU2/od n22I03fQ/wDPmqS6z7Oz7V9pj3+n6c+W7ckrv36fc/7m9j+1bw/9K0oIIBHB4SVPo2SMvpOHkAzv pZP9YCHfiFcVOcTGUoneJI+xKkkkkEqSSSSUpJJJJSkkkklKSSSSUrySWX+0m/8AOT9mz/2l9T+3 v4/zUlL7E+3+T93/AAUX+dOP/i+6kLsC3p7z+kxnb2D/AIN+v4O/KusXkHROq2dJ6lVmMktadtrB +dW76Q/u8165j305NFeRQ4PqtaHMcO4KufFOXOPOcgHoza/4XUftWwNiuzMkASeFiYv1u6Nk59mC LdjmO212v0rtPfa74+PK2yARB1BXKdc+ouLmOdkdNcMa86uqP804+UfR/Iq3LR5eRlHPKUOIeiQ2 B8Uyvo9WkvNmZv1u+rf6O1rzjt0AsHq0/wBl44+RWjj/AOMd4AGTggnu6uyP+i5p/Kp5fDM/zYjD PDpKEh+1HGOuj3CS41/+MfFA9mFYXeBeAPwBWfk/XzrOWfSwMdlLnaDaDbZ8u34IR+Gc2d4CA7yk K/BXHF7nP6jhdOoORmWtqrHE8uPg0ckqt0Tr2F1ql9mNLH1uh9T43Afmu07FcbifVP6wdavGT1Wx 1LDy+47rI8G19vnC7bpPRsDpFHo4dcE/zlrtXvP8pyGfDy2HGYjJ72e94fJHwSDInag3kznNY0uc Ya0SSeAAnXLfXnrgw8L9m0O/WcofpI5ZV3/zuPvVfBhlmyxxx/SO/YdSkmhbyv7fd/zp/bEn0/W4 /wCB/m4/zEliJLqfu2L93/Jez/gdmCz+NqXUfVH60fsx4wc1x+w2H2POvouPf+qe/wB65dJHNhhm xnHMWD9oPcKBINh9ta5r2h7CHNcJa4agg9wnXmH1f+tuZ0iKLQcjC/0RPuZ/xZ/gvQemda6b1Wvf h3B7vzqj7bG/FpXN81yOXlySRxw6TG317M0ZAt7nQqnf0bpORrdhUvJ7mts/eBKuJKrGUom4kx8j SXNZ9W+gsMjApnzbP5VeoxcbHEY9LKR4VtDf+pCIknSy5JfNOUv7xJVQUkmc5rGlzyGtGpJMABcv 1z684WG11HTYysnj1P8ABMPx/O+X3p2HBlzS4ccTL8h5lRIG7qdf6/i9FxfUsIfkvB9CidXHxPg0 LyzMzMjOybMrJdvutO5zv4DyCWZmZOdkOycqw23P+k535B4BBXR8lyUeWj+9kl80v2DwYZSvyUkk kri1SSSSSlIlHr+q37Pv9afZ6c758tuqSSB2P7dlPc9E/wCfm1vqbPR0j7b9KP7H6T711mP9q2D7 V6e/v6e6P+kkkuZ575z/ALm3/wAh+1nj9fql+Cy+p/8AOTaf2b9l/wCub9/y/NSSVfB84/m/+q/K k/X6PA9f/wCdO4/tj1vTnT/Q/L0/YsNJJdTy381H+a/6j8n0YDv1+qkkklMhSSSSSn//2Q==" preserveAspectRatio="xMidYMid meet" width="30" height="60" />
+ </g>
+ <g transform="translate(100, 0)">
+ <text y="-5">*YMax</text>&Viewport2;
+ <image xlink:href="data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAHgAA/+4ADkFkb2JlAGTAAAAAAf/b AIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBA QEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUw MDU1QEA/QEBAQEBAQEBAQEBA/8AAEQgAZABkAwEiAAIRAQMRAf/EAT8AAAEFAQEBAQEBAAAAAAAA AAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAABBAEDAgQCBQcGCAUD DDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1Rk RcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX 5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLhcoKSQ1MV Y3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0pbXF1eX1VmZ2hpam tsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A8/SSR8LCyc/JZi4rDZdYYa0flPgAgSACSaA1 JKkLWuc4NaC5x0AGpJXT9J+onUcwC3Od9jpOoYRutI/q/m/P7l1X1f8Aqth9HYLXgX5xHuuI0b5V g8fHlbixOa+LSsw5fQf5w7/QMscfdxcL6n9BwwP1cXvH5953/wDR+j+C1qsbHoEU1MqHgxob+RES WVPNlyG5zlP+8bXgAbBRAIgiR4Knk9G6TlgjIw6Xz32AO/zhBVxJNjOUTcZGJ8DSnk+pf4v8C4F/ T7XY1nZj/fX/AOSH4rjOq9E6l0mzZmVFrSYZa33Vu+Dv4L19Qvx6Mmp1GRW22p4hzHCQQtDl/imf GQMh96Hj830P8VpgDto+KJLqPrR9UX9M3ZuCDZgzL2cupn8rfP71y63sObHmgJ4zYP2g9ixEEGip JJJSoXa1znBrQS5xgAckleo/Vb6vM6Phh9oBzrwDc790cisfDv5rlfqJ0kZnUXZ1rZpw4LJ4Nrvo /wCbz9y9GWH8W5o8X3eB0GuTz6Blxx6qSSVDrPWcTo2J9pyZcXHbVU36T3eA/iVkwhKchCAMpS0A C9vpLiKP8YxNwGRhbaCdSx8vA+BABXZ42TTl49eTjuD6bWhzHDuCpc/K5sFe7DhEtjdj8FCQOyRJ Vuo9Qxum4lmZlO21V+GpcTw1o8SuQP8AjHd62mCPQn/Se+P82EsHKZ8wMsUOIR62Br9UGQG73CSq 9M6li9Uw2ZmK6a36EHRzXDlrh4hWlDKJjIxkKMTRBXLOa17Sx4DmuBDmnUEHsV5j9bfq/wDsfMFt AP2LIJNX8h3ev+5enqj1rplfVem3Yb43PE1OP5tjdWlWuR5o8vlBJ9E9Jjw7/RbKNh8fSRPQu9f7 PtPrb/T2d987dv3pLqLHfx+jA+ofU/CGH0HHkQ+8G9/9v6P/AEYW0h41Qox6qRxUxrB/ZEIi4/NM 5Ms5n9ORl9rYAoAKXEf4xqLicLIAJoaHsJ7B5gj7wF26Hk42Pl0ux8mtttLxDmOEgqTlc/sZoZa4 hG7HgdFSFinxVeo/Uui+n6v44ukby97Gnsxxlv38p6PqX9X6b/WGOXwZax7i5g/snn5rcAAAAEAc BXfiHxDHnxxx44yri4iZfkFkIEGy8v8A4waL7Oj1WVgmum4OtA7Atc0OPzK85XttlbLWOrsaHseC HNcJBB7ELCP1K+rxv9b7O6Jn0t7tn3TP4o8h8Rx4MXt5Iy0JMTHx7qlAk2Gl/i8ovr6ZkWvBFVtv 6Ke+0Q5w/J8l1ajVVXTW2qpoZWwQ1jRAAHYBSWfzGb3s08tcPGbpeBQpSSSSiS8d+xGf8/PU2/od n22I03fQ/wDPmqS6z7Oz7V9pj3+n6c+W7ckrv36fc/7m9j+1bw/9K0oIIBHB4SVPo2SMvpOHkAzv pZP9YCHfiFcVOcTGUoneJI+xKkkkkEqSSSSUpJJJJSkkkklKSSSSUrySWX+0m/8AOT9mz/2l9T+3 v4/zUlL7E+3+T93/AAUX+dOP/i+6kLsC3p7z+kxnb2D/AIN+v4O/KusXkHROq2dJ6lVmMktadtrB +dW76Q/u8165j305NFeRQ4PqtaHMcO4KufFOXOPOcgHoza/4XUftWwNiuzMkASeFiYv1u6Nk59mC LdjmO212v0rtPfa74+PK2yARB1BXKdc+ouLmOdkdNcMa86uqP804+UfR/Iq3LR5eRlHPKUOIeiQ2 B8Uyvo9WkvNmZv1u+rf6O1rzjt0AsHq0/wBl44+RWjj/AOMd4AGTggnu6uyP+i5p/Kp5fDM/zYjD PDpKEh+1HGOuj3CS41/+MfFA9mFYXeBeAPwBWfk/XzrOWfSwMdlLnaDaDbZ8u34IR+Gc2d4CA7yk K/BXHF7nP6jhdOoORmWtqrHE8uPg0ckqt0Tr2F1ql9mNLH1uh9T43Afmu07FcbifVP6wdavGT1Wx 1LDy+47rI8G19vnC7bpPRsDpFHo4dcE/zlrtXvP8pyGfDy2HGYjJ72e94fJHwSDInag3kznNY0uc Ya0SSeAAnXLfXnrgw8L9m0O/WcofpI5ZV3/zuPvVfBhlmyxxx/SO/YdSkmhbyv7fd/zp/bEn0/W4 /wCB/m4/zEliJLqfu2L93/Jez/gdmCz+NqXUfVH60fsx4wc1x+w2H2POvouPf+qe/wB65dJHNhhm xnHMWD9oPcKBINh9ta5r2h7CHNcJa4agg9wnXmH1f+tuZ0iKLQcjC/0RPuZ/xZ/gvQemda6b1Wvf h3B7vzqj7bG/FpXN81yOXlySRxw6TG317M0ZAt7nQqnf0bpORrdhUvJ7mts/eBKuJKrGUom4kx8j SXNZ9W+gsMjApnzbP5VeoxcbHEY9LKR4VtDf+pCIknSy5JfNOUv7xJVQUkmc5rGlzyGtGpJMABcv 1z684WG11HTYysnj1P8ABMPx/O+X3p2HBlzS4ccTL8h5lRIG7qdf6/i9FxfUsIfkvB9CidXHxPg0 LyzMzMjOybMrJdvutO5zv4DyCWZmZOdkOycqw23P+k535B4BBXR8lyUeWj+9kl80v2DwYZSvyUkk kri1SSSSSlIlHr+q37Pv9afZ6c758tuqSSB2P7dlPc9E/wCfm1vqbPR0j7b9KP7H6T711mP9q2D7 V6e/v6e6P+kkkuZ575z/ALm3/wAh+1nj9fql+Cy+p/8AOTaf2b9l/wCub9/y/NSSVfB84/m/+q/K k/X6PA9f/wCdO4/tj1vTnT/Q/L0/YsNJJdTy381H+a/6j8n0YDv1+qkkklMhSSSSSn//2Q==" preserveAspectRatio="xMaxYMax meet" width="30" height="60" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.12 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-desc-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-desc-02-t.svg
new file mode 100644
index 0000000000..140f9e2ad8
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-desc-02-t.svg
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN" owner="CN" desc="Test the CSS2 font-maching algorithm against a set of SVG fonts."
+ status="accepted"
+ approved="yes" version="$Revision: 1.6 $" testname="$RCSfile: fonts-desc-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This tests the behaviour of CSS font matching based on font-variant attribute.</p>
+ <p>The first line of text should be 'square' 'triangle'. The small-caps font should match the second text element.</p>
+ <p>The second line of text should be 'square' 'triangle'. The second line is used to ensure that the order of font specification does not effect the selection of these fonts.</p>
+ <p>The third line of text should be 'square', 'diamond', 'square', 'diamond'. This shows that the correct font is selected when a font in the list does not support the variant required. Note that the fonts provide no x-height so scaling (allowed by CSS) cannot be used to simulate a small cap from a regular font.</p>
+ <p>The last line of test can be 'square', 'a', 'a' (from a fallback font), 'diamond'. The first 'a' can be replaced with a smallcaps 'A', if there is a smallcaps font installed or if synthesis is supported.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-desc-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font horiz-adv-x="500">
+ <font-face font-family="SVGFont1" units-per-em="1000" ascent="800" descent="200" alphabetic="200" />
+ <missing-glyph horiz-adv-x="500" d="M0 0L500 0L500 1000L0 1000M50 50L50 950L450 950L450 50Z" />
+ <glyph unicode=" " glyph-name="space" />
+ <glyph unicode="a" glyph-name="square" d="M0 250L500 250L500 750L0 750Z" />
+ </font>
+ <font horiz-adv-x="500">
+ <font-face font-family="SVGFont1" font-variant="small-caps" units-per-em="1000" ascent="800" descent="200" alphabetic="200" />
+ <missing-glyph horiz-adv-x="500" d="M0 0L500 0L500 1000L0 1000M50 50L50 950L450 950L450 50Z" />
+ <glyph unicode=" " glyph-name="space" />
+ <glyph unicode="a" glyph-name="upward-triangle" d="M0 0L500 0L250 900Z" />
+ </font>
+ <font horiz-adv-x="500">
+ <font-face font-family="SVGFont2" font-variant="small-caps" units-per-em="1000" ascent="800" descent="200" alphabetic="200" />
+ <missing-glyph horiz-adv-x="500" d="M0 0L500 0L500 1000L0 1000M50 50L50 950L450 950L450 50Z" />
+ <glyph unicode=" " glyph-name="space" />
+ <glyph unicode="a" glyph-name="upward-triangle" d="M0 0L500 0L250 900Z" />
+ </font>
+ <font horiz-adv-x="500">
+ <font-face font-family="SVGFont2" units-per-em="1000" ascent="800" descent="200" alphabetic="200" />
+ <missing-glyph horiz-adv-x="500" d="M0 0L500 0L500 1000L0 1000M50 50L50 950L450 950L450 50Z" />
+ <glyph unicode=" " glyph-name="space" />
+ <glyph unicode="a" glyph-name="square" d="M0 250L500 250L500 750L0 750Z" />
+ </font>
+ <font horiz-adv-x="500">
+ <font-face font-family="SVGFont4" font-variant="normal" units-per-em="1000" ascent="800" descent="200" alphabetic="200" />
+ <missing-glyph horiz-adv-x="500" d="M0 0L500 0L500 1000L0 1000M50 50L50 950L450 950L450 50Z" />
+ <glyph unicode=" " glyph-name="space" />
+ <glyph unicode="a" glyph-name="square" d="M0 250L500 250L500 750L0 750Z" />
+ </font>
+ <font horiz-adv-x="500">
+ <font-face font-family="SVGFont5" font-variant="small-caps" units-per-em="1000" ascent="800" descent="200" alphabetic="200" />
+ <missing-glyph horiz-adv-x="500" d="M0 0L500 0L500 1000L0 1000M50 50L50 950L450 950L450 50Z" />
+ <glyph unicode=" " glyph-name="space" />
+ <glyph unicode="a" glyph-name="diamond" d="M0 500L250 250L500 500L250 750Z" />
+ </font>
+ </defs>
+ <g font-size="30">
+ <!-- This should produce a square followed by a triangle -->
+ <text x="50" y="50" font-family="SVGFont1">a</text>
+ <text x="100" y="50" font-family="SVGFont1" font-variant="small-caps">a</text>
+ <!-- This should produce a square followed by a triangle -->
+ <text x="50" y="100" font-family="SVGFont2">a</text>
+ <text x="100" y="100" font-family="SVGFont2" font-variant="small-caps">a</text>
+ <!-- This should produce a square, diamond, square, diamond. -->
+ <text x="50" y="150" font-family="SVGFont5,SVGFont4" font-variant="normal">a</text>
+ <text x="100" y="150" font-family="SVGFont5,SVGFont4" font-variant="small-caps">a</text>
+ <text x="150" y="150" font-family="SVGFont4,SVGFont5" font-variant="normal">a</text>
+ <text x="200" y="150" font-family="SVGFont4,SVGFont5" font-variant="small-caps">a</text>
+ <!-- This should produce a square, 'a', 'a', diamond. Or a small-caps version of the 'A' instead of the first lower-case 'a' if synethesis is supported -->
+ <text x="50" y="200" font-family="SVGFont4" font-variant="normal">a</text>
+ <text x="100" y="200" font-family="SVGFont4" font-variant="small-caps">a</text>
+ <text x="150" y="200" font-family="SVGFont5" font-variant="normal">a</text>
+ <text x="200" y="200" font-family="SVGFont5" font-variant="small-caps">a</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-01-t.svg
new file mode 100644
index 0000000000..36927a1f6f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-01-t.svg
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="Dean Jackson" desc="Basic test of embedded fonts using glyph outlines"
+ status="accepted"
+ approved="yes" version="$Revision: 1.8 $" testname="$RCSfile: fonts-elem-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This is a basic test for embedded SVG fonts. The font &quot;Comic Sans&quot; (available from Microsoft) has been converted into an SVG font and embedded in the SVG file. The test contains two text areas, each with the character string "Ay&#xd6;@&#xe7;" drawn at the same font size.</p>
+ <p>The upper area contains the glyphs from the embedded font placed in the SVG file as path elements. Each glyph is placed at the location it would be if rendered using normal text rendering (ie. the horizontal advance between characters has been preserved).</p>
+ <p>The lower area contains the text string rendered using the embedded SVG font. It should appear exactly the same as the upper text area, ie. font size, character baseline and horizontal advance should be the same.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-elem-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font horiz-adv-x="959">
+ <font-face font-family="TestComic" units-per-em="2048" panose-1="3 15 7 2 3 3 2 2 2 4" ascent="2257" descent="-597" alphabetic="0" />
+ <missing-glyph horiz-adv-x="1024" d="M128 0V1638H896V0H128zM256 128H768V1510H256V128z" />
+ <glyph unicode="@" horiz-adv-x="1907" d="M1306 412Q1200 412 1123 443T999 535Q945 482 894 455T793 428Q682 428 584 518T485 717Q485 902 630 1055T961 1208Q1003 1208 1031 1177T1059 1102Q1059 1042 959 1013Q826 975 771 926Q690 855 690 717Q690 688 717 661Q748 631 794 633Q881 637 955 795Q1022 933 1074 933Q1116 933 1142 902T1168 826Q1168 806 1162 766T1155 706Q1155 641 1211 624Q1233 617 1306 617Q1443 617 1498 684Q1548 744 1548 883Q1548 1128 1351 1283Q1171 1425 921 1425Q630 1425 465 1205Q316 1009 316 712Q316 438 491 250Q673 54 959 54Q1040 54 1142 85L1317 150Q1361 166 1374 166Q1415 166 1445 134T1475 58Q1475 -37 1262 -96Q1101 -140 961 -140Q820 -140 673 -86T420 60Q110 328 110 712Q110 1096 322 1354Q547 1630 921 1630Q1259 1630 1500 1427Q1753 1212 1753 883Q1753 658 1643 537Q1528 412 1306 412z" />
+ <glyph unicode="A" horiz-adv-x="1498" d="M1250 -30Q1158 -30 1090 206Q1064 296 1025 521Q923 507 758 471L492 416Q442 285 321 33Q289 -23 234 -23Q194 -23 163 6T131 78Q131 126 282 443Q265 469 265 503Q265 584 363 607Q477 821 651 1099Q888 1478 946 1478Q1025 1478 1054 1368L1117 1032L1266 337L1323 179Q1352 98 1352 71Q1352 28 1321 -1T1250 -30zM897 1113L611 652Q732 683 978 727L897 1113z" />
+ <glyph unicode="y" horiz-adv-x="1066" d="M1011 892L665 144Q537 -129 469 -313L403 -507Q377 -579 313 -579Q271 -579 241 -552T210 -483Q210 -383 426 96L68 785L23 858Q-4 904 -4 935Q-4 976 27 1007T98 1038Q144 1038 169 1003Q339 767 534 331L682 676Q762 855 836 984Q868 1040 920 1040Q961 1040 992 1011T1024 942Q1024 920 1011 892z" />
+ <glyph unicode="Ö" horiz-adv-x="1635" d="M802 -61Q520 -61 324 108Q116 288 116 572Q116 918 321 1201Q550 1515 892 1515Q1221 1515 1381 1367Q1548 1213 1548 881Q1548 535 1360 257Q1144 -61 802 -61zM892 1310Q647 1310 477 1066Q320 842 320 572Q320 379 463 258Q600 144 802 144Q1045 144 1203 389Q1344 608 1344 881Q1344 1120 1237 1217Q1135 1310 892 1310zM682 1848Q813 1848 813 1743Q813 1713 769 1685Q729 1660 694 1660Q571 1660 571 1763Q571 1792 608 1820T682 1848zM1221 1856Q1255 1856 1290 1825T1325 1763Q1325 1671 1182 1671Q1141 1671 1109 1692Q1073 1716 1073 1755Q1073 1824 1118 1844Q1143 1856 1221 1856z" />
+ <glyph unicode="ç" horiz-adv-x="1052" d="M770 -196Q770 -320 710 -382T528 -445Q443 -445 367 -413Q271 -371 271 -298Q271 -244 339 -244Q375 -244 420 -268T517 -293Q566 -292 590 -269T614 -201Q614 -153 577 -115T463 -48Q304 -12 208 104Q105 227 105 404Q105 607 240 823Q390 1063 578 1063Q676 1063 797 1017Q950 958 950 873Q950 835 925 806T863 776Q834 776 813 793T771 828Q712 875 578 875Q476 875 376 693Q285 526 285 404Q285 272 375 196Q459 125 591 125Q651 125 719 157L835 219Q865 235 878 235Q915 235 942 206T969 138Q969 35 713 -40Q742 -78 756 -117T770 -196z" />
+ </font>
+ </defs>
+ <!-- ===================================================================== -->
+ <!-- Define the font for embedding - using Microsoft's "Comic Sans MS" -->
+ <!-- This is an SVG Font version of Comic. The Comic font license -->
+ <!-- allows editable and installable font embedding. -->
+ <!-- Only need to embed the characters that are used in the test -->
+ <!-- ===================================================================== -->
+ <text fill="black" stroke="none" font-size="35" x="56" y="35">Basic SVG font element</text>
+ <!-- ====================================================================== -->
+ <!-- First place the glyphs by hand -->
+ <!-- ====================================================================== -->
+ <g fill="black" stroke="none">
+ <text x="30" y="130" font-size="18">Placed Glyphs</text>
+ <!-- translate to text position and flip y axis (glyphs are drawn -->
+ <!-- upside down -->
+ <g transform="translate(165,140) scale(1, -1)">
+ <line x1="0" y1="0" x2="210" y2="0" stroke-width="1" stroke="#888888" />
+ <!-- fontsize / units-per-em == 60 / 2048 == 0.029296875 -->
+ <g transform="scale(0.029296875)">
+ <!-- uppercase A -->
+ <line x1="0" y1="-3500" x2="0" y2="2000" stroke-width="50" stroke="#888888" />
+ <path d="M1250 -30Q1158 -30 1090 206Q1064 296 1025 521Q923 507 758 471L492 416Q442 285 321 33Q289 -23 234 -23Q194 -23 163 6T131 78Q131 126 282 443Q265 469 265 503Q265 584 363 607Q477 821 651 1099Q888 1478 946 1478Q1025 1478 1054 1368L1117 1032L1266 337L1323 179Q1352 98 1352 71Q1352 28 1321 -1T1250 -30zM897 1113L611 652Q732 683 978 727L897 1113z" />
+ <!-- lowercase y -->
+ <line x1="1498" y1="-3500" x2="1498" y2="2000" stroke-width="50" stroke="#888888" />
+ <path transform="translate(1498,0)" d="M1011 892L665 144Q537 -129 469 -313L403 -507Q377 -579 313 -579Q271 -579 241 -552T210 -483Q210 -383 426 96L68 785L23 858Q-4 904 -4 935Q-4 976 27 1007T98 1038Q144 1038 169 1003Q339 767 534 331L682 676Q762 855 836 984Q868 1040 920 1040Q961 1040 992 1011T1024 942Q1024 920 1011 892z" />
+ <!-- unicode 00D6 -->
+ <line x1="2564" y1="-3500" x2="2564" y2="2000" stroke-width="50" stroke="#888888" />
+ <path transform="translate(2564,0)" d="M802 -61Q520 -61 324 108Q116 288 116 572Q116 918 321 1201Q550 1515 892 1515Q1221 1515 1381 1367Q1548 1213 1548 881Q1548 535 1360 257Q1144 -61 802 -61zM892 1310Q647 1310 477 1066Q320 842 320 572Q320 379 463 258Q600 144 802 144Q1045 144 1203 389Q1344 608 1344 881Q1344 1120 1237 1217Q1135 1310 892 1310zM682 1848Q813 1848 813 1743Q813 1713 769 1685Q729 1660 694 1660Q571 1660 571 1763Q571 1792 608 1820T682 1848zM1221 1856Q1255 1856 1290 1825T1325 1763Q1325 1671 1182 1671Q1141 1671 1109 1692Q1073 1716 1073 1755Q1073 1824 1118 1844Q1143 1856 1221 1856z" />
+ <!-- @ sign -->
+ <line x1="4199" y1="-3500" x2="4199" y2="2000" stroke-width="50" stroke="#888888" />
+ <path transform="translate(4199,0)" d="M1306 412Q1200 412 1123 443T999 535Q945 482 894 455T793 428Q682 428 584 518T485 717Q485 902 630 1055T961 1208Q1003 1208 1031 1177T1059 1102Q1059 1042 959 1013Q826 975 771 926Q690 855 690 717Q690 688 717 661Q748 631 794 633Q881 637 955 795Q1022 933 1074 933Q1116 933 1142 902T1168 826Q1168 806 1162 766T1155 706Q1155 641 1211 624Q1233 617 1306 617Q1443 617 1498 684Q1548 744 1548 883Q1548 1128 1351 1283Q1171 1425 921 1425Q630 1425 465 1205Q316 1009 316 712Q316 438 491 250Q673 54 959 54Q1040 54 1142 85L1317 150Q1361 166 1374 166Q1415 166 1445 134T1475 58Q1475 -37 1262 -96Q1101 -140 961 -140Q820 -140 673 -86T420 60Q110 328 110 712Q110 1096 322 1354Q547 1630 921 1630Q1259 1630 1500 1427Q1753 1212 1753 883Q1753 658 1643 537Q1528 412 1306 412z" />
+ <!-- unicode 00E7 -->
+ <line x1="6106" y1="-3500" x2="6106" y2="2000" stroke-width="50" stroke="#888888" />
+ <path transform="translate(6106,0)" d="M770 -196Q770 -320 710 -382T528 -445Q443 -445 367 -413Q271 -371 271 -298Q271 -244 339 -244Q375 -244 420 -268T517 -293Q566 -292 590 -269T614 -201Q614 -153 577 -115T463 -48Q304 -12 208 104Q105 227 105 404Q105 607 240 823Q390 1063 578 1063Q676 1063 797 1017Q950 958 950 873Q950 835 925 806T863 776Q834 776 813 793T771 828Q712 875 578 875Q476 875 376 693Q285 526 285 404Q285 272 375 196Q459 125 591 125Q651 125 719 157L835 219Q865 235 878 235Q915 235 942 206T969 138Q969 35 713 -40Q742 -78 756 -117T770 -196z" />
+ <line x1="7158" y1="-3500" x2="7158" y2="2000" stroke-width="50" stroke="#888888" />
+ </g>
+ </g>
+ </g>
+ <text x="65" y="210" font-size="18">SVG Font</text>
+ <g transform="translate(165, 220)" font-family="TestComic" font-size="60" fill="black" stroke="none">
+ <line x1="0" y1="0" x2="210" y2="0" stroke-width="1" stroke="#888888" />
+ <text>AyÖ@ç</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-02-t.svg
new file mode 100644
index 0000000000..484765b7cf
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-02-t.svg
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="Dean Jackson" desc="Basic test of embedded fonts using glyph outlines" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: fonts-elem-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This is an accuracy test for embedded SVG fonts. The font &quot;Comic Sans&quot; (available from Microsoft) has been converted into an SVG font and embedded in the SVG file. The test contains two text areas, each with the character string "Ay&#xd6;@&#xe7;" drawn at the same font size.</p>
+ <p>The upper area has the placed glyphs as path elements filled with white over a solid black background (creating a white cutout). The embedded SVG font text is then drawn over the cutout. An implementation that passes this test should completely fill the cutout, leaving a solid black area (some slight antialiasing effects may remain).</p>
+ <p>The lower area is the reverse of the upper area, with the placed black glyphs filling the cutout created by white SVG font text. An implementation that passes this test should completely fill the cutout, leaving a solid black area (some slight antialiasing effects may remain).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-elem-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font horiz-adv-x="959">
+ <font-face font-family="TestComic" units-per-em="2048" panose-1="3 15 7 2 3 3 2 2 2 4" ascent="2257" descent="-597" alphabetic="0" />
+ <missing-glyph horiz-adv-x="1024" d="M128 0V1638H896V0H128zM256 128H768V1510H256V128z" />
+ <glyph unicode="@" horiz-adv-x="1907" d="M1306 412Q1200 412 1123 443T999 535Q945 482 894 455T793 428Q682 428 584 518T485 717Q485 902 630 1055T961 1208Q1003 1208 1031 1177T1059 1102Q1059 1042 959 1013Q826 975 771 926Q690 855 690 717Q690 688 717 661Q748 631 794 633Q881 637 955 795Q1022 933 1074 933Q1116 933 1142 902T1168 826Q1168 806 1162 766T1155 706Q1155 641 1211 624Q1233 617 1306 617Q1443 617 1498 684Q1548 744 1548 883Q1548 1128 1351 1283Q1171 1425 921 1425Q630 1425 465 1205Q316 1009 316 712Q316 438 491 250Q673 54 959 54Q1040 54 1142 85L1317 150Q1361 166 1374 166Q1415 166 1445 134T1475 58Q1475 -37 1262 -96Q1101 -140 961 -140Q820 -140 673 -86T420 60Q110 328 110 712Q110 1096 322 1354Q547 1630 921 1630Q1259 1630 1500 1427Q1753 1212 1753 883Q1753 658 1643 537Q1528 412 1306 412z" />
+ <glyph unicode="A" horiz-adv-x="1498" d="M1250 -30Q1158 -30 1090 206Q1064 296 1025 521Q923 507 758 471L492 416Q442 285 321 33Q289 -23 234 -23Q194 -23 163 6T131 78Q131 126 282 443Q265 469 265 503Q265 584 363 607Q477 821 651 1099Q888 1478 946 1478Q1025 1478 1054 1368L1117 1032L1266 337L1323 179Q1352 98 1352 71Q1352 28 1321 -1T1250 -30zM897 1113L611 652Q732 683 978 727L897 1113z" />
+ <glyph unicode="y" horiz-adv-x="1066" d="M1011 892L665 144Q537 -129 469 -313L403 -507Q377 -579 313 -579Q271 -579 241 -552T210 -483Q210 -383 426 96L68 785L23 858Q-4 904 -4 935Q-4 976 27 1007T98 1038Q144 1038 169 1003Q339 767 534 331L682 676Q762 855 836 984Q868 1040 920 1040Q961 1040 992 1011T1024 942Q1024 920 1011 892z" />
+ <glyph unicode="Ö" horiz-adv-x="1635" d="M802 -61Q520 -61 324 108Q116 288 116 572Q116 918 321 1201Q550 1515 892 1515Q1221 1515 1381 1367Q1548 1213 1548 881Q1548 535 1360 257Q1144 -61 802 -61zM892 1310Q647 1310 477 1066Q320 842 320 572Q320 379 463 258Q600 144 802 144Q1045 144 1203 389Q1344 608 1344 881Q1344 1120 1237 1217Q1135 1310 892 1310zM682 1848Q813 1848 813 1743Q813 1713 769 1685Q729 1660 694 1660Q571 1660 571 1763Q571 1792 608 1820T682 1848zM1221 1856Q1255 1856 1290 1825T1325 1763Q1325 1671 1182 1671Q1141 1671 1109 1692Q1073 1716 1073 1755Q1073 1824 1118 1844Q1143 1856 1221 1856z" />
+ <glyph unicode="ç" horiz-adv-x="1052" d="M770 -196Q770 -320 710 -382T528 -445Q443 -445 367 -413Q271 -371 271 -298Q271 -244 339 -244Q375 -244 420 -268T517 -293Q566 -292 590 -269T614 -201Q614 -153 577 -115T463 -48Q304 -12 208 104Q105 227 105 404Q105 607 240 823Q390 1063 578 1063Q676 1063 797 1017Q950 958 950 873Q950 835 925 806T863 776Q834 776 813 793T771 828Q712 875 578 875Q476 875 376 693Q285 526 285 404Q285 272 375 196Q459 125 591 125Q651 125 719 157L835 219Q865 235 878 235Q915 235 942 206T969 138Q969 35 713 -40Q742 -78 756 -117T770 -196z" />
+ </font>
+ </defs>
+ <!-- ===================================================================== -->
+ <!-- Define the font for embedding - using Microsoft's "Comic Sans MS" -->
+ <!-- This is an SVG Font version of Comic. The Comic font license -->
+ <!-- allows editable and installable font embedding. -->
+ <!-- Only need to embed the characters that are used in the test -->
+ <!-- ===================================================================== -->
+ <text fill="black" stroke="none" font-size="35" x="28" y="35">SVG font element accuracy</text>
+ <rect x="165" y="80" width="220" height="165" fill="black" />
+ <text x="7" y="130" font-size="18">SVG over Glyphs</text>
+ <!-- translate to text position and flip y axis (glyphs are drawn -->
+ <!-- upside down -->
+ <g transform="translate(165,140) scale(1, -1)" fill="white">
+ <!-- fontsize / units-per-em == 60 / 2048 == 0.029296875 -->
+ <g transform="scale(0.029296875)">
+ <!-- uppercase A -->
+ <path d="M1250 -30Q1158 -30 1090 206Q1064 296 1025 521Q923 507 758 471L492 416Q442 285 321 33Q289 -23 234 -23Q194 -23 163 6T131 78Q131 126 282 443Q265 469 265 503Q265 584 363 607Q477 821 651 1099Q888 1478 946 1478Q1025 1478 1054 1368L1117 1032L1266 337L1323 179Q1352 98 1352 71Q1352 28 1321 -1T1250 -30zM897 1113L611 652Q732 683 978 727L897 1113z" />
+ <!-- lowercase y -->
+ <path transform="translate(1498,0)" d="M1011 892L665 144Q537 -129 469 -313L403 -507Q377 -579 313 -579Q271 -579 241 -552T210 -483Q210 -383 426 96L68 785L23 858Q-4 904 -4 935Q-4 976 27 1007T98 1038Q144 1038 169 1003Q339 767 534 331L682 676Q762 855 836 984Q868 1040 920 1040Q961 1040 992 1011T1024 942Q1024 920 1011 892z" />
+ <!-- unicode 00D6 -->
+ <path transform="translate(2564,0)" d="M802 -61Q520 -61 324 108Q116 288 116 572Q116 918 321 1201Q550 1515 892 1515Q1221 1515 1381 1367Q1548 1213 1548 881Q1548 535 1360 257Q1144 -61 802 -61zM892 1310Q647 1310 477 1066Q320 842 320 572Q320 379 463 258Q600 144 802 144Q1045 144 1203 389Q1344 608 1344 881Q1344 1120 1237 1217Q1135 1310 892 1310zM682 1848Q813 1848 813 1743Q813 1713 769 1685Q729 1660 694 1660Q571 1660 571 1763Q571 1792 608 1820T682 1848zM1221 1856Q1255 1856 1290 1825T1325 1763Q1325 1671 1182 1671Q1141 1671 1109 1692Q1073 1716 1073 1755Q1073 1824 1118 1844Q1143 1856 1221 1856z" />
+ <!-- @ sign -->
+ <path transform="translate(4199,0)" d="M1306 412Q1200 412 1123 443T999 535Q945 482 894 455T793 428Q682 428 584 518T485 717Q485 902 630 1055T961 1208Q1003 1208 1031 1177T1059 1102Q1059 1042 959 1013Q826 975 771 926Q690 855 690 717Q690 688 717 661Q748 631 794 633Q881 637 955 795Q1022 933 1074 933Q1116 933 1142 902T1168 826Q1168 806 1162 766T1155 706Q1155 641 1211 624Q1233 617 1306 617Q1443 617 1498 684Q1548 744 1548 883Q1548 1128 1351 1283Q1171 1425 921 1425Q630 1425 465 1205Q316 1009 316 712Q316 438 491 250Q673 54 959 54Q1040 54 1142 85L1317 150Q1361 166 1374 166Q1415 166 1445 134T1475 58Q1475 -37 1262 -96Q1101 -140 961 -140Q820 -140 673 -86T420 60Q110 328 110 712Q110 1096 322 1354Q547 1630 921 1630Q1259 1630 1500 1427Q1753 1212 1753 883Q1753 658 1643 537Q1528 412 1306 412z" />
+ <!-- unicode 00E7 -->
+ <path transform="translate(6106,0)" d="M770 -196Q770 -320 710 -382T528 -445Q443 -445 367 -413Q271 -371 271 -298Q271 -244 339 -244Q375 -244 420 -268T517 -293Q566 -292 590 -269T614 -201Q614 -153 577 -115T463 -48Q304 -12 208 104Q105 227 105 404Q105 607 240 823Q390 1063 578 1063Q676 1063 797 1017Q950 958 950 873Q950 835 925 806T863 776Q834 776 813 793T771 828Q712 875 578 875Q476 875 376 693Q285 526 285 404Q285 272 375 196Q459 125 591 125Q651 125 719 157L835 219Q865 235 878 235Q915 235 942 206T969 138Q969 35 713 -40Q742 -78 756 -117T770 -196z" />
+ </g>
+ </g>
+ <g transform="translate(165, 140)" font-family="TestComic" font-size="60" fill="black" stroke="none">
+ <text>AyÖ@ç</text>
+ </g>
+ <text x="7" y="210" font-size="18">Glyphs over SVG</text>
+ <g transform="translate(165, 210)" font-family="TestComic" font-size="60" fill="white" stroke="none">
+ <text>AyÖ@ç</text>
+ </g>
+ <!-- translate to text position and flip y axis (glyphs are drawn -->
+ <!-- upside down -->
+ <g transform="translate(165,210) scale(1, -1)" fill="black">
+ <!-- fontsize / units-per-em == 60 / 2048 == 0.029296875 -->
+ <g transform="scale(0.029296875)">
+ <!-- uppercase A -->
+ <path d="M1250 -30Q1158 -30 1090 206Q1064 296 1025 521Q923 507 758 471L492 416Q442 285 321 33Q289 -23 234 -23Q194 -23 163 6T131 78Q131 126 282 443Q265 469 265 503Q265 584 363 607Q477 821 651 1099Q888 1478 946 1478Q1025 1478 1054 1368L1117 1032L1266 337L1323 179Q1352 98 1352 71Q1352 28 1321 -1T1250 -30zM897 1113L611 652Q732 683 978 727L897 1113z" />
+ <!-- lowercase y -->
+ <path transform="translate(1498,0)" d="M1011 892L665 144Q537 -129 469 -313L403 -507Q377 -579 313 -579Q271 -579 241 -552T210 -483Q210 -383 426 96L68 785L23 858Q-4 904 -4 935Q-4 976 27 1007T98 1038Q144 1038 169 1003Q339 767 534 331L682 676Q762 855 836 984Q868 1040 920 1040Q961 1040 992 1011T1024 942Q1024 920 1011 892z" />
+ <!-- unicode 00D6 -->
+ <path transform="translate(2564,0)" d="M802 -61Q520 -61 324 108Q116 288 116 572Q116 918 321 1201Q550 1515 892 1515Q1221 1515 1381 1367Q1548 1213 1548 881Q1548 535 1360 257Q1144 -61 802 -61zM892 1310Q647 1310 477 1066Q320 842 320 572Q320 379 463 258Q600 144 802 144Q1045 144 1203 389Q1344 608 1344 881Q1344 1120 1237 1217Q1135 1310 892 1310zM682 1848Q813 1848 813 1743Q813 1713 769 1685Q729 1660 694 1660Q571 1660 571 1763Q571 1792 608 1820T682 1848zM1221 1856Q1255 1856 1290 1825T1325 1763Q1325 1671 1182 1671Q1141 1671 1109 1692Q1073 1716 1073 1755Q1073 1824 1118 1844Q1143 1856 1221 1856z" />
+ <!-- @ sign -->
+ <path transform="translate(4199,0)" d="M1306 412Q1200 412 1123 443T999 535Q945 482 894 455T793 428Q682 428 584 518T485 717Q485 902 630 1055T961 1208Q1003 1208 1031 1177T1059 1102Q1059 1042 959 1013Q826 975 771 926Q690 855 690 717Q690 688 717 661Q748 631 794 633Q881 637 955 795Q1022 933 1074 933Q1116 933 1142 902T1168 826Q1168 806 1162 766T1155 706Q1155 641 1211 624Q1233 617 1306 617Q1443 617 1498 684Q1548 744 1548 883Q1548 1128 1351 1283Q1171 1425 921 1425Q630 1425 465 1205Q316 1009 316 712Q316 438 491 250Q673 54 959 54Q1040 54 1142 85L1317 150Q1361 166 1374 166Q1415 166 1445 134T1475 58Q1475 -37 1262 -96Q1101 -140 961 -140Q820 -140 673 -86T420 60Q110 328 110 712Q110 1096 322 1354Q547 1630 921 1630Q1259 1630 1500 1427Q1753 1212 1753 883Q1753 658 1643 537Q1528 412 1306 412z" />
+ <!-- unicode 00E7 -->
+ <path transform="translate(6106,0)" d="M770 -196Q770 -320 710 -382T528 -445Q443 -445 367 -413Q271 -371 271 -298Q271 -244 339 -244Q375 -244 420 -268T517 -293Q566 -292 590 -269T614 -201Q614 -153 577 -115T463 -48Q304 -12 208 104Q105 227 105 404Q105 607 240 823Q390 1063 578 1063Q676 1063 797 1017Q950 958 950 873Q950 835 925 806T863 776Q834 776 813 793T771 828Q712 875 578 875Q476 875 376 693Q285 526 285 404Q285 272 375 196Q459 125 591 125Q651 125 719 157L835 219Q865 235 878 235Q915 235 942 206T969 138Q969 35 713 -40Q742 -78 756 -117T770 -196z" />
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-03-t.svg
new file mode 100644
index 0000000000..01551e2937
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-03-t.svg
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="Dean Jackson" desc="Basic test of external embedded fonts with font-face-src"
+ status="accepted"
+ approved="yes" version="$Revision: 1.7 $" testname="$RCSfile: fonts-elem-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This is a basic test for external SVG fonts. The font &quot;Comic Sans&quot; (available from Microsoft) has been converted into an SVG font and placed in an external SVG file referenced by a font-face-src element. The test contains two text areas, each with the character string "Ay&#xd6;@&#xe7;" drawn at the same font size.</p>
+ <p>The upper area contains the glyphs from the font placed in the SVG file as path elements. Each glyph is placed at the location it would be if rendered using normal text rendering (ie. the horizontal advance between characters has been preserved).</p>
+ <p>The lower area contains the text string rendered using the external SVG font. It should appear exactly the same as the upper text area, ie. font size, character baseline and horizontal advance should be the same.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-elem-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <!--style type="text/css"> <![CDATA[ @font-face { font-family: 'TestComic'; font-weight: normal; font-style: normal; src: url("../images/ext-TestComic.svg#Font") format(svg) } ]]> </style-->
+ <font-face font-family="TestComic">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/ext-TestComic.svg#Font" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <text fill="black" stroke="none" font-size="30" x="26" y="35">External SVG font element (xml)</text>
+ <!-- ====================================================================== -->
+ <!-- First place the glyphs by hand -->
+ <!-- ====================================================================== -->
+ <g fill="black" stroke="none">
+ <text x="31" y="130" font-size="18">Placed Glyphs</text>
+ <!-- translate to text position and flip y axis (glyphs are drawn -->
+ <!-- upside down -->
+ <g transform="translate(165,140) scale(1, -1)">
+ <line x1="0" y1="0" x2="210" y2="0" stroke-width="1" stroke="#888888" />
+ <!-- fontsize / units-per-em == 60 / 2048 == 0.029296875 -->
+ <g transform="scale(0.029296875)">
+ <!-- uppercase A -->
+ <line x1="0" y1="-3500" x2="0" y2="2000" stroke-width="50" stroke="#888888" />
+ <path d="M1250 -30Q1158 -30 1090 206Q1064 296 1025 521Q923 507 758 471L492 416Q442 285 321 33Q289 -23 234 -23Q194 -23 163 6T131 78Q131 126 282 443Q265 469 265 503Q265 584 363 607Q477 821 651 1099Q888 1478 946 1478Q1025 1478 1054 1368L1117 1032L1266 337L1323 179Q1352 98 1352 71Q1352 28 1321 -1T1250 -30zM897 1113L611 652Q732 683 978 727L897 1113z" />
+ <!-- lowercase y -->
+ <line x1="1498" y1="-3500" x2="1498" y2="2000" stroke-width="50" stroke="#888888" />
+ <path transform="translate(1498,0)" d="M1011 892L665 144Q537 -129 469 -313L403 -507Q377 -579 313 -579Q271 -579 241 -552T210 -483Q210 -383 426 96L68 785L23 858Q-4 904 -4 935Q-4 976 27 1007T98 1038Q144 1038 169 1003Q339 767 534 331L682 676Q762 855 836 984Q868 1040 920 1040Q961 1040 992 1011T1024 942Q1024 920 1011 892z" />
+ <!-- unicode 00D6 -->
+ <line x1="2564" y1="-3500" x2="2564" y2="2000" stroke-width="50" stroke="#888888" />
+ <path transform="translate(2564,0)" d="M802 -61Q520 -61 324 108Q116 288 116 572Q116 918 321 1201Q550 1515 892 1515Q1221 1515 1381 1367Q1548 1213 1548 881Q1548 535 1360 257Q1144 -61 802 -61zM892 1310Q647 1310 477 1066Q320 842 320 572Q320 379 463 258Q600 144 802 144Q1045 144 1203 389Q1344 608 1344 881Q1344 1120 1237 1217Q1135 1310 892 1310zM682 1848Q813 1848 813 1743Q813 1713 769 1685Q729 1660 694 1660Q571 1660 571 1763Q571 1792 608 1820T682 1848zM1221 1856Q1255 1856 1290 1825T1325 1763Q1325 1671 1182 1671Q1141 1671 1109 1692Q1073 1716 1073 1755Q1073 1824 1118 1844Q1143 1856 1221 1856z" />
+ <!-- @ sign -->
+ <line x1="4199" y1="-3500" x2="4199" y2="2000" stroke-width="50" stroke="#888888" />
+ <path transform="translate(4199,0)" d="M1306 412Q1200 412 1123 443T999 535Q945 482 894 455T793 428Q682 428 584 518T485 717Q485 902 630 1055T961 1208Q1003 1208 1031 1177T1059 1102Q1059 1042 959 1013Q826 975 771 926Q690 855 690 717Q690 688 717 661Q748 631 794 633Q881 637 955 795Q1022 933 1074 933Q1116 933 1142 902T1168 826Q1168 806 1162 766T1155 706Q1155 641 1211 624Q1233 617 1306 617Q1443 617 1498 684Q1548 744 1548 883Q1548 1128 1351 1283Q1171 1425 921 1425Q630 1425 465 1205Q316 1009 316 712Q316 438 491 250Q673 54 959 54Q1040 54 1142 85L1317 150Q1361 166 1374 166Q1415 166 1445 134T1475 58Q1475 -37 1262 -96Q1101 -140 961 -140Q820 -140 673 -86T420 60Q110 328 110 712Q110 1096 322 1354Q547 1630 921 1630Q1259 1630 1500 1427Q1753 1212 1753 883Q1753 658 1643 537Q1528 412 1306 412z" />
+ <!-- unicode 00E7 -->
+ <line x1="6106" y1="-3500" x2="6106" y2="2000" stroke-width="50" stroke="#888888" />
+ <path transform="translate(6106,0)" d="M770 -196Q770 -320 710 -382T528 -445Q443 -445 367 -413Q271 -371 271 -298Q271 -244 339 -244Q375 -244 420 -268T517 -293Q566 -292 590 -269T614 -201Q614 -153 577 -115T463 -48Q304 -12 208 104Q105 227 105 404Q105 607 240 823Q390 1063 578 1063Q676 1063 797 1017Q950 958 950 873Q950 835 925 806T863 776Q834 776 813 793T771 828Q712 875 578 875Q476 875 376 693Q285 526 285 404Q285 272 375 196Q459 125 591 125Q651 125 719 157L835 219Q865 235 878 235Q915 235 942 206T969 138Q969 35 713 -40Q742 -78 756 -117T770 -196z" />
+ <line x1="7158" y1="-3500" x2="7158" y2="2000" stroke-width="50" stroke="#888888" />
+ </g>
+ </g>
+ </g>
+ <text x="67" y="210" font-size="18">SVG Font</text>
+ <g transform="translate(165, 220)" font-family="TestComic" font-size="60" fill="black" stroke="none">
+ <line x1="0" y1="0" x2="210" y2="0" stroke-width="1" stroke="#888888" />
+ <text>AyÖ@ç</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-06-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-06-t.svg
new file mode 100644
index 0000000000..7a6dd8769b
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-elem-06-t.svg
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN" owner="VH" desc="validates that the font element's horiz-adv-x is used" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: fonts-elem-06-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test validates that the font element's horiz-adv-x is used as the default glyph's advance when there is no glyph advance specified. All fonts have a units-per-em of 1000.</p>
+ <p>The first row shows a layout with a default adavance of 1000. Glyphs have no advance so the 1000 default should be used.</p>
+ <p>The second row shows a layout with a default adavance of 2000. Glyphs have no advance so the 2000 default should be used.</p>
+ <p>The last row shows a layout with a default adavance of 0. Glyphs have a specified advance so the 0 default should be ignored.</p>
+ <p>Reference blue markers show the expected glyph positions.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-elem-06-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font xml:id="advance1000" horiz-adv-x="1000">
+ <font-face font-family="advance1000" units-per-em="1000" ascent="1000" descent="0" alphabetic="0" />
+ <missing-glyph d="M50 0V800H750V0H50ZM700 50V750H100V50H700Z" />
+ <glyph unicode="1" glyph-name="gl_1" d="M 0 0 L 250 0 L 250 250 L 0 250 Z" />
+ <glyph unicode="2" glyph-name="gl_2" d="M 0 0 L 500 0 L 500 500 L 0 500 Z" />
+ </font>
+ <font xml:id="advance2000" horiz-adv-x="2000">
+ <font-face font-family="advance2000" units-per-em="1000" ascent="1000" descent="0" alphabetic="0" />
+ <missing-glyph d="M50 0V800H750V0H50ZM700 50V750H100V50H700Z" />
+ <glyph unicode="1" glyph-name="gl_1" d="M 0 0 L 250 0 L 250 250 L 0 250 Z" />
+ <glyph unicode="2" glyph-name="gl_2" d="M 0 0 L 500 0 L 500 500 L 0 500 Z" />
+ </font>
+ <font xml:id="advanceIgnored" horiz-adv-x="0">
+ <font-face font-family="advanceIgnored" units-per-em="1000" ascent="1000" descent="0" alphabetic="0" />
+ <missing-glyph horiz-adv-x="800" d="M50 0V800H750V0H50ZM700 50V750H100V50H700Z" />
+ <glyph unicode="1" glyph-name="gl_1" horiz-adv-x="3000" d="M 0 0 L 250 0 L 250 250 L 0 250 Z" />
+ <glyph unicode="2" glyph-name="gl_2" horiz-adv-x="3000" d="M 0 0 L 500 0 L 500 500 L 0 500 Z" />
+ </font>
+ <g xml:id="marker">
+ <line y2="-20" stroke="red" />
+ <rect x="-4" y="-4" width="8" height="8" fill="#8888ff" />
+ </g>
+ </defs>
+ <text x="240" y="50" text-anchor="middle" font-size="30">&lt;font&gt; horiz-adv-x</text>
+ <g transform="translate(20, 120)" font-size="14">
+ <g>
+ <text>horiz-adv-x=1000</text>
+ <use xlink:href="#marker" x="240" />
+ <use xlink:href="#marker" x="270" />
+ <text x="240" font-family="advance1000" font-size="30">12</text>
+ </g>
+ <g transform="translate(0, 40)">
+ <text>horiz-adv-x=2000</text>
+ <use xlink:href="#marker" x="240" />
+ <use xlink:href="#marker" x="300" />
+ <text x="240" font-family="advance2000" font-size="30">12</text>
+ </g>
+ <g transform="translate(0, 80)">
+ <text>horiz-adv-x=1000 but ignored</text>
+ <use xlink:href="#marker" x="240" />
+ <use xlink:href="#marker" x="330" />
+ <text x="240" font-family="advanceIgnored" font-size="30">12</text>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-02-t.svg
new file mode 100644
index 0000000000..8504417554
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-02-t.svg
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="CN" desc="Test on arabic-form" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: fonts-glyph-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The first subtest tests the arabic-form attribute and should produce a 'downward triangle', a 'space', a 'square', a 'diamond' and then an 'upward triangle' in this order. Remembering that arabic text is right to left.</p>
+ <p>The second subtest is the same, but with glyphs for the letter khah. It should match the reference image.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-glyph-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font horiz-adv-x="300">
+ <font-face font-family="SVGFont" units-per-em="1000" ascent="800" descent="200" alphabetic="200" />
+ <missing-glyph horiz-adv-x="500" d="M0 0L500 0L500 1000L0 1000M50 50L50 950L450 950L450 50Z" />
+ <glyph unicode=" " glyph-name="space" horiz-adv-x="300" />
+ <glyph unicode="ښ" glyph-name="downward-triangle" horiz-adv-x="500" arabic-form="isolated" d="M0 900L500 900L250 0Z" />
+ <glyph unicode="ښ" glyph-name="square" horiz-adv-x="500" arabic-form="initial" d="M0 250L500 250L500 750L0 750Z" />
+ <glyph unicode="ښ" glyph-name="diamond" horiz-adv-x="500" arabic-form="medial" d="M0 500L250 250L500 500L250 750Z" />
+ <glyph unicode="ښ" glyph-name="upward-triangle" horiz-adv-x="500" arabic-form="terminal" d="M0 0L500 0L250 900Z" />
+ </font>
+ <font horiz-adv-x="573">
+ <font-face font-family="SVGAr" units-per-em="1000" panose-1="5 1 1 1 1 1 1 1 1 1" ascent="1025" descent="-399" alphabetic="0" />
+ <missing-glyph horiz-adv-x="500" d="M31 0V800H469V0H31ZM438 31V769H62V31H438Z" />
+ <glyph unicode=" " glyph-name="space" horiz-adv-x="370" />
+ <glyph unicode="خ" glyph-name="khah-isolated" arabic-form="isolated" horiz-adv-x="562" d="M309 360Q309 353 297 335T271 317Q260 317 227 337T194 370Q194 380 205 397T232 415Q246 415 277 395T309 360ZM518 -265Q516 -269 509 -275Q507 -277 502 -281Q447 -319 424 -330Q356 -363 281 -363Q228 -363 186 -347T110 -294Q69 -249 54 -199Q44 -167 44 -127Q44 -96 50 -65T76 12Q88 39 110 70Q152 127 152 137Q152 151 148 156T121 161Q95 161 85 156Q72 146 62 140Q44 128 35 130Q35 138 35 146Q37 151 43 162Q77 208 98 219T159 231Q170 231 234 221Q255 218 298 210H340Q347 210 382 218T425 230T435 235Q446 239 449 234Q454 226 444 189T426 152Q418 152 393 154T360 156Q327 156 297 149T228 120Q180 93 142 36Q96 -33 96 -110Q96 -209 168 -257Q223 -294 300 -294Q343 -294 371 -291Q429 -285 489 -267Q506 -260 511 -260Q514 -262 518 -265Z" />
+ <glyph unicode="خ" glyph-name="khah-initial" arabic-form="initial" horiz-adv-x="728" d="M297 372Q297 365 285 347T259 329Q248 329 215 349T182 382Q182 392 193 409T220 427Q234 427 265 407T297 372ZM600 0H0V68H373Q396 68 396 86Q396 89 394 95Q377 137 347 159Q308 188 243 188Q210 188 183 171Q165 160 157 158T145 156Q138 156 138 164L140 174Q145 196 191 220Q228 240 269 240Q313 240 355 221T447 160Q488 120 530 81Q543 73 563 71T609 68Q619 68 620 68T625 68Q645 68 645 46Q645 30 633 15T600 0Z" />
+ <glyph unicode="خ" glyph-name="khah-medial" arabic-form="medial" horiz-adv-x="625" d="M296 376Q296 369 284 351T258 333Q247 333 214 353T181 386Q181 396 192 413T219 431Q233 431 264 411T296 376ZM625 0H0V68H373Q396 68 396 86Q396 89 394 95Q377 137 347 159Q308 188 243 188Q210 188 183 171Q165 160 157 158T145 156Q138 156 138 164L140 174Q145 196 191 220Q228 240 269 240Q313 240 355 221T447 160Q488 120 530 81Q543 73 563 71T609 68Q619 68 620 68T625 68V0Z" />
+ <glyph unicode="خ" glyph-name="khah-terminal" arabic-form="terminal" horiz-adv-x="514" d="M296 352Q296 345 284 327T258 309Q247 309 214 329T181 362Q181 372 192 389T219 407Q233 407 264 387T296 352ZM514 0H375Q313 0 298 64T261 128Q209 128 153 62Q91 -12 91 -101Q91 -199 162 -243Q220 -279 319 -279Q367 -279 390 -276T463 -259Q466 -258 475 -255T488 -252Q490 -252 491 -254T489 -263Q484 -272 466 -286T433 -307Q408 -320 401 -323Q349 -344 277 -344Q169 -344 104 -274Q44 -210 44 -118Q44 -88 51 -53T73 14Q80 31 97 56Q132 108 132 118Q132 127 126 134T110 141Q92 141 85 137Q72 127 59 117Q49 112 44 112Q38 112 38 119Q38 122 40 128Q49 156 80 182Q116 212 157 212Q170 212 188 208Q232 198 258 198H320Q345 198 357 201Q374 207 383 209T398 214T412 216Q420 216 421 212Q424 202 414 170T396 137Q394 137 382 140T362 143Q346 143 337 135T327 104Q327 91 341 80T379 68H514V0Z" />
+ </font>
+ </defs>
+ <g font-family="SVGFont" font-size="80">
+ <!-- This should produce 'downward triangle' 'space' 'square' 'diamond' 'upward-triangle' -->
+ <text x="100" y="100">ښ ښښښ</text>
+ </g>
+ <g font-family="SVGAr" font-size="80">
+ <!-- this should produce isolated khah, followed by initial,medial and terminal khah -->
+ <text x="100" y="200">خ خخخ</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-03-t.svg
new file mode 100644
index 0000000000..4d868ae783
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-03-t.svg
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="CN" desc="Test on the lang attribute" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: fonts-glyph-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This files tests the lang attribute support of the glyph element. The test should produce an upward-triangle for the first (en) test element and a square for the second (fr) and third
+ (fr-ca) text element. In the third case, a glyph for fr is also suitable for a more specific language text fr-ca. In the fourth case, no suitable language specific or general glyph is
+ provided by the test so a fallback font for the letter 'a' should be used. A triangle or square must not be displayed in the fourth case.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-glyph-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font horiz-adv-x="500">
+ <font-face font-family="SVGFont" units-per-em="1000" ascent="800" descent="200" alphabetic="200" />
+ <missing-glyph horiz-adv-x="500" d="M0 0L500 0L500 1000L0 1000M50 50L50 950L450 950L450 50Z" />
+ <glyph unicode=" " glyph-name="space" />
+ <glyph unicode="a" glyph-name="upward-triangle" lang="en" d="M0 0L500 0L250 900Z" />
+ <glyph unicode="a" glyph-name="square" lang="fr" d="M0 250L500 250L500 750L0 750Z" />
+ </font>
+ </defs>
+ <g font-family="SVGFont" font-size="50">
+ <!-- Should produce an upward pointing triangle -->
+ <text x="50" y="50" xml:lang="en">a</text>
+ <!-- Should produce a square -->
+ <text x="50" y="120" xml:lang="fr">a</text>
+ <!-- Should also produce a square -->
+ <text x="50" y="190" xml:lang="fr-ca">a</text>
+ <!-- Should fall back to another font -->
+ <text x="50" y="260" xml:lang="de">a</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-04-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-04-t.svg
new file mode 100644
index 0000000000..4522d3adf8
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-04-t.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/" reviewer="CL" owner="CN" desc="Test the glyph selection rules" status="accepted" approved="yes" version="$Revision: 1.6 $" testname="$RCSfile: fonts-glyph-04-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This tests that glyph selection is done in the order in the definition of the font element. The first line of text should be represented by two triangles and an 'l'. The second line should be represented by a square.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-glyph-04-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font horiz-adv-x="500">
+ <font-face font-family="SVGFont1" units-per-em="1000" ascent="800" descent="200" alphabetic="200" />
+ <glyph unicode="f" glyph-name="upward-triangle" d="M0 0L500 0L250 900Z" />
+ <glyph unicode="ffl" glyph-name="square" d="M0 250L500 250L500 750L0 750Z" />
+ </font>
+ <font horiz-adv-x="500">
+ <font-face font-family="SVGFont2" units-per-em="1000" ascent="800" descent="200" alphabetic="200" />
+ <glyph unicode="ffl" glyph-name="square 2" d="M0 250L500 250L500 750L0 750Z" />
+ <glyph unicode="f" glyph-name="upward-triangle 2" d="M0 0L500 0L250 900Z" />
+ </font>
+ </defs>
+ <text x="100" y="100" font-size="50" font-family="SVGFont1">ffl</text>
+ <text x="100" y="200" font-size="50" font-family="SVGFont2">ffl</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-201-t.svg
new file mode 100644
index 0000000000..64e701f24f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-201-t.svg
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="CL" desc="ligature matching in document order" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: fonts-glyph-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test that ligatures are always used, and only used, when they occur before the
+ glyphs for characters they are ligatures of. The word "fjord" is displayed twice;
+ the top one must use the fj ligature and the bottom one must not; the top of the letter f overlaps the
+ dot of the letter i..
+ </p>
+ <p>
+ Two fonts are defined, almost identical; in one the fj ligature is the
+ first glyph defined, in the second one it is the last glyph.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-glyph-201-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font xml:id="Fjord-BoldOblique-nolig" horiz-adv-x="312" >
+ <font-face
+ font-family="Fjord-nl"
+ font-weight="700"
+ font-style="oblique"
+ font-stretch="normal"
+ units-per-em="1000"
+ panose-1="2 0 8 3 0 0 0 0 0 0"
+ ascent="800"
+ descent="-200"
+ x-height="447"
+ cap-height="-1e+10"
+ bbox="-92 -234 639 726.333"
+ underline-thickness="50"
+ underline-position="-100"
+ slope="-9.8"
+ unicode-range="U+0064-U+0072"
+ />
+ <missing-glyph horiz-adv-x="432"
+ d="M33 0v666h333v-666h-333zM66 33h267v600h-267v-600z" />
+ <glyph glyph-name="f" unicode="f"
+ d="M171 429c3.33299 25.333 7.66701 48.333 13 69l11 46c20.667 62.667 53 109 97 139c8.66699 6.66699 21.667 13.667 39 21c28.667 12 62.333 19 101 21c33.333 2 62 -0.666992 86 -8h1c16 -5.33301 30 -12.667 42 -22c6.66699 -4 11.333 -8.66699 14 -14
+ c1.33301 -2 1.66699 -9 1 -21v-1l-2 -48c-2.66699 -10.667 -6 -19 -10 -25c-15.333 -22.667 -37 -32 -65 -28c-12 2 -22.333 6.33301 -31 13c-6.66699 5.33301 -12 11.667 -16 19c-9.33301 15.333 -11.333 32.333 -6 51c1.33301 4.66699 3.33301 9.66699 6 15l3 10
+ c-0.666992 2.66699 -3.66699 5.66699 -9 9c-6.66699 5.33301 -14.667 9.66699 -24 13l-11 3c-3.33301 0 -9.66699 -3.66699 -19 -11c-12.667 -9.33301 -25.333 -22.667 -38 -40c-22.667 -31.333 -39.333 -67.667 -50 -109l-6 -38l-11 -64h116l-6 -18l-5 -8l-10 -2h-20h-80
+ l-14 -83l-27 -157l-12 -70l-5 -33v-1c1.33299 -17.3333 15 -28.6667 41 -34l12 -2l-3 -20h-236l3 20c27.3333 0 47.6667 9.6667 61 29l4 6l5 22l6 38l49 285h-60l6 17l4 9l16 2h39z" />
+ <glyph glyph-name="j" unicode="j"
+ d="M248 644c4.66701 1.33301 11.333 1.33301 20 0c14 -3.33301 25 -10 33 -20c15.333 -18.667 17.667 -39.333 7 -62v-2v0c-4.66699 -8.66699 -10.667 -15.667 -18 -21c-6.66699 -4.66699 -14.667 -7.66699 -24 -9h-1c-22 -4.66699 -39.667 1.66699 -53 19l-1 1
+ c-15.333 19.333 -17.667 40.333 -7 63l1 1c3.33299 8 8.33299 14.333 15 19c8.66701 6 18 9.66699 28 11zM82 385l4 18l14 3l32 4l92 21l29 10l17 5l20 1l-59 -343l-12 -73c-8 -46 -18.333 -79.3333 -31 -100c-38.667 -66.667 -108 -116 -208 -148
+ c-24 -7.33299 -48 -13 -72 -17l3 20c19.3333 4 37.6667 10.333 55 19c55.3333 28 95 76.667 119 146l5 16c4.6667 15.3333 11.667 53 21 113l22 124l17 103l5 28c1.33299 12 1.66701 19.667 1 23c-8 25.333 -32 34.333 -72 27h-2z" />
+ <glyph glyph-name="o" unicode="o" horiz-adv-x="554"
+ d="M346 447c15.333 0.666992 32 0 50 -2c42 -3.33301 75.333 -16 100 -38c20.667 -16.667 36 -40.333 46 -71c15.333 -46 15.667 -95.333 1 -148l-2 -6c-20.667 -69.333 -58.333 -121.667 -113 -157l-22 -12c-29.333 -14.6667 -66 -24.3333 -110 -29
+ c-58 -4.6667 -105 2.6667 -141 22c-8 4 -17 10.3333 -27 19c-45.3333 41.3333 -62.6667 101 -52 179c2.6667 19.333 7.3333 38.333 14 57l20 44c34 65.333 84.333 108 151 128c19.333 5.33301 47.667 10 85 14zM341 416c-6 0 -14 -3.33301 -24 -10
+ c-21.333 -12 -39.333 -26.667 -54 -44c-46.667 -52.667 -71 -113 -73 -181c-0.667007 -25.333 2.33299 -49.667 9 -73c11.333 -35.3333 29.333 -61.6667 54 -79c15.333 -10 26 -15 32 -15c4.66699 0 13 3.3333 25 10c21.333 12 39.333 26.6667 54 44
+ c46.667 52 71 112.333 73 181c0.666992 24.667 -2 48.333 -8 71c-11.333 36 -29.667 63 -55 81c-12 9.33301 -23 14.333 -33 15z" />
+ <glyph glyph-name="r" unicode="r" horiz-adv-x="445"
+ d="M318 422c-1.33301 5.33301 2 9.66699 10 13c8.66699 4.66699 23.333 8.33301 44 11c67.333 9.33301 110 -2.66699 128 -36l7 -19c2 -9.33301 2.66699 -18 2 -26c-1.33301 -8.66699 -10 -15.667 -26 -21c-20 -5.33301 -39.667 -8 -59 -8c-11.333 0 -19.667 1 -25 3
+ c-5.33301 1.33301 -7.33301 8 -6 20v3c-1.33301 17.333 -7.33301 31.333 -18 42c-6 6 -11.333 9 -16 9c-4.66699 -0.666992 -12.333 -5.33301 -23 -14c-17.333 -14 -32.333 -33.333 -45 -58c-12.667 -25.333 -22.333 -50.333 -29 -75
+ c-4.66699 -16.667 -12.667 -58.333 -24 -125l-10 -56l-4 -28c1.33299 -17.3333 15 -28.6667 41 -34l12 -2l-3 -20h-236l3 20c26.6667 0 47 9.6667 61 29l2 4c1.333 1.3333 3.667 9.3333 7 24l7 43l26 149l10 60c2.66701 15.333 2.33299 26.333 -1 33
+ c-8 16 -24.667 24 -50 24l-21 -2l4 18l12 3h1l33 4c30 4.66699 60.333 11.667 91 21l30 10l17 5l20 1l-12 -72h1c8.66699 18.667 21.667 34 39 46v1zM278 375h-1h1z" />
+ <glyph glyph-name="d" unicode="d" horiz-adv-x="562"
+ d="M380 666l50 5l81 19l31 10l22 7l20 1l-10 -60l-21 -123l-58 -339l-15 -91l-4 -23c-1.33301 -10 -1.66699 -16.3333 -1 -19c5.33301 -19.3333 22 -30 50 -32h1h1l-3 -20h-147l1 86h-1c-3.33301 -11.3333 -9.66699 -23.3333 -19 -36c-18.667 -29.3333 -41 -49 -67 -59
+ c-11.333 -4 -26 -6.6667 -44 -8c-14 -1.3333 -28 -1.3333 -42 0c-37.333 3.3333 -66 14.6667 -86 34c-26 25.3333 -41 63.6667 -45 115c-6 72 11.3333 139.667 52 203l2 3c20 30.667 43.333 54 70 70c30 18 65 29.667 105 35c23.333 2.66699 41 0.333008 53 -7
+ c22 -14 30.667 -35.333 26 -64l-1 -6l-8 -19c-3.33301 -3.33301 -5.33301 -5 -6 -5l-8 4l-14 10c6.66699 10 10 18.333 10 25v1c0 16 -6.66699 26.667 -20 32c-5.33301 2 -11 2.33301 -17 1c-4 -0.666992 -11 -4.33301 -21 -11c-14 -10.667 -27.333 -23.667 -40 -39
+ c-39.333 -50 -61 -109 -65 -177c-2 -29.333 0 -55.667 6 -79c8.66701 -36.6667 24.333 -63 47 -79c13.333 -10 23.667 -14.6667 31 -14c6 0.6667 15 5.3333 27 14c13.333 10.6667 26.333 27 39 49c14 24 25 54.333 33 91l22 119l31 180l16 98l5 28l1 19
+ c-3.33301 19.333 -18.667 30.333 -46 33h-6l-21 -2z" />
+ <glyph glyph-name="fjlig" unicode="fj" horiz-adv-x="624"
+ d="M639 633v-23c-5.33331 -25.3333 -20.3333 -41.6667 -45 -49c-18.6667 -6 -36.3333 -4.33331 -53 5c-8.66669 4.66669 -15 10 -19 16c-6 6.66669 -10 15 -12 25c-2 11.3333 -2.33334 21 -1 29c2 9.33331 6.66669 19 14 29c-26.6667 14 -45.6667 22.3333 -57 25
+ c-10 2.66669 -17.6667 3.66669 -23 3c-4.66666 0 -12.3333 -3 -23 -9c-15.3333 -8.66669 -30.6667 -20.3333 -46 -35c-33.3333 -33.3333 -56 -71 -68 -113l-9 -45l-10 -62h312l-23 -137l-34 -201l-11 -64l-9 -46c-4 -12.6667 -11.6667 -26.3333 -23 -41l-1 -2
+ c-17.3333 -22 -45 -44 -83 -66l-102 -57c-15.3333 -10 -29 -20.3333 -41 -31h-1c-5.33334 5.33333 -8.33334 9.66667 -9 13v1c0 1.33333 2.33334 4.33333 7 9l22 19c40.6667 36.6667 69.6667 69 87 97c12 19.3333 20.3333 36 25 50c4 12.6667 8 32.3333 12 59l13 76l35 203
+ l15 90h-196l-15 -87l-24 -142l-13 -77l-6 -34v-4c1.33333 -17.3333 15 -28.6667 41 -34l12 -2l-3 -20h-236l3 20c27.3333 0 47.6667 9.66667 61 29l4 6l5 22l6 38l49 285h-60l6 17l4 9l16 2h39c7.33333 62.6667 21.6667 113 43 151c12.6667 21.3333 25.6667 39.3333 39 54
+ c54.6667 58.6667 130 89.3333 226 92c13.3333 0.666687 27 0.333313 41 -1c34 -2 64.6667 -10.3333 92 -25c10 -4 17.6667 -16.6667 23 -38c2.66669 -9.33331 4 -19 4 -29z" />
+ </font>
+ <font xml:id="Fjord-BoldOblique-lig" horiz-adv-x="312" >
+ <font-face
+ font-family="Fjord-wl"
+ font-weight="700"
+ font-style="oblique"
+ font-stretch="normal"
+ units-per-em="1000"
+ panose-1="2 0 8 3 0 0 0 0 0 0"
+ ascent="800"
+ descent="-200"
+ x-height="447"
+ cap-height="-1e+10"
+ bbox="-92 -234 639 726.333"
+ underline-thickness="50"
+ underline-position="-100"
+ slope="-9.8"
+ unicode-range="U+0064-U+0072"
+ />
+ <missing-glyph horiz-adv-x="432"
+ d="M33 0v666h333v-666h-333zM66 33h267v600h-267v-600z" />
+ <glyph glyph-name="fjlig" unicode="fj" horiz-adv-x="624"
+ d="M639 633v-23c-5.33331 -25.3333 -20.3333 -41.6667 -45 -49c-18.6667 -6 -36.3333 -4.33331 -53 5c-8.66669 4.66669 -15 10 -19 16c-6 6.66669 -10 15 -12 25c-2 11.3333 -2.33334 21 -1 29c2 9.33331 6.66669 19 14 29c-26.6667 14 -45.6667 22.3333 -57 25
+ c-10 2.66669 -17.6667 3.66669 -23 3c-4.66666 0 -12.3333 -3 -23 -9c-15.3333 -8.66669 -30.6667 -20.3333 -46 -35c-33.3333 -33.3333 -56 -71 -68 -113l-9 -45l-10 -62h312l-23 -137l-34 -201l-11 -64l-9 -46c-4 -12.6667 -11.6667 -26.3333 -23 -41l-1 -2
+ c-17.3333 -22 -45 -44 -83 -66l-102 -57c-15.3333 -10 -29 -20.3333 -41 -31h-1c-5.33334 5.33333 -8.33334 9.66667 -9 13v1c0 1.33333 2.33334 4.33333 7 9l22 19c40.6667 36.6667 69.6667 69 87 97c12 19.3333 20.3333 36 25 50c4 12.6667 8 32.3333 12 59l13 76l35 203
+ l15 90h-196l-15 -87l-24 -142l-13 -77l-6 -34v-4c1.33333 -17.3333 15 -28.6667 41 -34l12 -2l-3 -20h-236l3 20c27.3333 0 47.6667 9.66667 61 29l4 6l5 22l6 38l49 285h-60l6 17l4 9l16 2h39c7.33333 62.6667 21.6667 113 43 151c12.6667 21.3333 25.6667 39.3333 39 54
+ c54.6667 58.6667 130 89.3333 226 92c13.3333 0.666687 27 0.333313 41 -1c34 -2 64.6667 -10.3333 92 -25c10 -4 17.6667 -16.6667 23 -38c2.66669 -9.33331 4 -19 4 -29z" />
+ <glyph glyph-name="f" unicode="f"
+ d="M171 429c3.33299 25.333 7.66701 48.333 13 69l11 46c20.667 62.667 53 109 97 139c8.66699 6.66699 21.667 13.667 39 21c28.667 12 62.333 19 101 21c33.333 2 62 -0.666992 86 -8h1c16 -5.33301 30 -12.667 42 -22c6.66699 -4 11.333 -8.66699 14 -14
+ c1.33301 -2 1.66699 -9 1 -21v-1l-2 -48c-2.66699 -10.667 -6 -19 -10 -25c-15.333 -22.667 -37 -32 -65 -28c-12 2 -22.333 6.33301 -31 13c-6.66699 5.33301 -12 11.667 -16 19c-9.33301 15.333 -11.333 32.333 -6 51c1.33301 4.66699 3.33301 9.66699 6 15l3 10
+ c-0.666992 2.66699 -3.66699 5.66699 -9 9c-6.66699 5.33301 -14.667 9.66699 -24 13l-11 3c-3.33301 0 -9.66699 -3.66699 -19 -11c-12.667 -9.33301 -25.333 -22.667 -38 -40c-22.667 -31.333 -39.333 -67.667 -50 -109l-6 -38l-11 -64h116l-6 -18l-5 -8l-10 -2h-20h-80
+ l-14 -83l-27 -157l-12 -70l-5 -33v-1c1.33299 -17.3333 15 -28.6667 41 -34l12 -2l-3 -20h-236l3 20c27.3333 0 47.6667 9.6667 61 29l4 6l5 22l6 38l49 285h-60l6 17l4 9l16 2h39z" />
+ <glyph glyph-name="j" unicode="j"
+ d="M248 644c4.66701 1.33301 11.333 1.33301 20 0c14 -3.33301 25 -10 33 -20c15.333 -18.667 17.667 -39.333 7 -62v-2v0c-4.66699 -8.66699 -10.667 -15.667 -18 -21c-6.66699 -4.66699 -14.667 -7.66699 -24 -9h-1c-22 -4.66699 -39.667 1.66699 -53 19l-1 1
+ c-15.333 19.333 -17.667 40.333 -7 63l1 1c3.33299 8 8.33299 14.333 15 19c8.66701 6 18 9.66699 28 11zM82 385l4 18l14 3l32 4l92 21l29 10l17 5l20 1l-59 -343l-12 -73c-8 -46 -18.333 -79.3333 -31 -100c-38.667 -66.667 -108 -116 -208 -148
+ c-24 -7.33299 -48 -13 -72 -17l3 20c19.3333 4 37.6667 10.333 55 19c55.3333 28 95 76.667 119 146l5 16c4.6667 15.3333 11.667 53 21 113l22 124l17 103l5 28c1.33299 12 1.66701 19.667 1 23c-8 25.333 -32 34.333 -72 27h-2z" />
+ <glyph glyph-name="o" unicode="o" horiz-adv-x="554"
+ d="M346 447c15.333 0.666992 32 0 50 -2c42 -3.33301 75.333 -16 100 -38c20.667 -16.667 36 -40.333 46 -71c15.333 -46 15.667 -95.333 1 -148l-2 -6c-20.667 -69.333 -58.333 -121.667 -113 -157l-22 -12c-29.333 -14.6667 -66 -24.3333 -110 -29
+ c-58 -4.6667 -105 2.6667 -141 22c-8 4 -17 10.3333 -27 19c-45.3333 41.3333 -62.6667 101 -52 179c2.6667 19.333 7.3333 38.333 14 57l20 44c34 65.333 84.333 108 151 128c19.333 5.33301 47.667 10 85 14zM341 416c-6 0 -14 -3.33301 -24 -10
+ c-21.333 -12 -39.333 -26.667 -54 -44c-46.667 -52.667 -71 -113 -73 -181c-0.667007 -25.333 2.33299 -49.667 9 -73c11.333 -35.3333 29.333 -61.6667 54 -79c15.333 -10 26 -15 32 -15c4.66699 0 13 3.3333 25 10c21.333 12 39.333 26.6667 54 44
+ c46.667 52 71 112.333 73 181c0.666992 24.667 -2 48.333 -8 71c-11.333 36 -29.667 63 -55 81c-12 9.33301 -23 14.333 -33 15z" />
+ <glyph glyph-name="r" unicode="r" horiz-adv-x="445"
+ d="M318 422c-1.33301 5.33301 2 9.66699 10 13c8.66699 4.66699 23.333 8.33301 44 11c67.333 9.33301 110 -2.66699 128 -36l7 -19c2 -9.33301 2.66699 -18 2 -26c-1.33301 -8.66699 -10 -15.667 -26 -21c-20 -5.33301 -39.667 -8 -59 -8c-11.333 0 -19.667 1 -25 3
+ c-5.33301 1.33301 -7.33301 8 -6 20v3c-1.33301 17.333 -7.33301 31.333 -18 42c-6 6 -11.333 9 -16 9c-4.66699 -0.666992 -12.333 -5.33301 -23 -14c-17.333 -14 -32.333 -33.333 -45 -58c-12.667 -25.333 -22.333 -50.333 -29 -75
+ c-4.66699 -16.667 -12.667 -58.333 -24 -125l-10 -56l-4 -28c1.33299 -17.3333 15 -28.6667 41 -34l12 -2l-3 -20h-236l3 20c26.6667 0 47 9.6667 61 29l2 4c1.333 1.3333 3.667 9.3333 7 24l7 43l26 149l10 60c2.66701 15.333 2.33299 26.333 -1 33
+ c-8 16 -24.667 24 -50 24l-21 -2l4 18l12 3h1l33 4c30 4.66699 60.333 11.667 91 21l30 10l17 5l20 1l-12 -72h1c8.66699 18.667 21.667 34 39 46v1zM278 375h-1h1z" />
+ <glyph glyph-name="d" unicode="d" horiz-adv-x="562"
+ d="M380 666l50 5l81 19l31 10l22 7l20 1l-10 -60l-21 -123l-58 -339l-15 -91l-4 -23c-1.33301 -10 -1.66699 -16.3333 -1 -19c5.33301 -19.3333 22 -30 50 -32h1h1l-3 -20h-147l1 86h-1c-3.33301 -11.3333 -9.66699 -23.3333 -19 -36c-18.667 -29.3333 -41 -49 -67 -59
+ c-11.333 -4 -26 -6.6667 -44 -8c-14 -1.3333 -28 -1.3333 -42 0c-37.333 3.3333 -66 14.6667 -86 34c-26 25.3333 -41 63.6667 -45 115c-6 72 11.3333 139.667 52 203l2 3c20 30.667 43.333 54 70 70c30 18 65 29.667 105 35c23.333 2.66699 41 0.333008 53 -7
+ c22 -14 30.667 -35.333 26 -64l-1 -6l-8 -19c-3.33301 -3.33301 -5.33301 -5 -6 -5l-8 4l-14 10c6.66699 10 10 18.333 10 25v1c0 16 -6.66699 26.667 -20 32c-5.33301 2 -11 2.33301 -17 1c-4 -0.666992 -11 -4.33301 -21 -11c-14 -10.667 -27.333 -23.667 -40 -39
+ c-39.333 -50 -61 -109 -65 -177c-2 -29.333 0 -55.667 6 -79c8.66701 -36.6667 24.333 -63 47 -79c13.333 -10 23.667 -14.6667 31 -14c6 0.6667 15 5.3333 27 14c13.333 10.6667 26.333 27 39 49c14 24 25 54.333 33 91l22 119l31 180l16 98l5 28l1 19
+ c-3.33301 19.333 -18.667 30.333 -46 33h-6l-21 -2z" />
+
+ </font>
+ </defs>
+ <g fill="#127" fill-opacity="0.4" stroke="#fff" stroke-width="0.5">
+ <text x="160" y="260" font-family="Fjord-nl" font-weight="700" font-style="oblique"
+ font-size="120">fjord</text>
+ <text x="160" y="130" font-family="Fjord-wl" font-weight="700" font-style="oblique"
+ font-size="120">fjord</text>
+ <g font-size="14" fill-opacity="0.8" stroke="none">
+ <text x="20" y="100" >The Fjord fonts</text>
+ <text x="20" y="120">are derived from</text>
+ <text x="20" y="140">Gladiator</text>
+ <text x="20" y="160">by Bert Bos</text>
+ <text x="20" y="180">and are used</text>
+ <text x="20" y="200">by kind permission.</text>
+ </g>
+ <!-- No norwegian blue parrots were harmed n the making of this test -->
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-202-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-202-t.svg
new file mode 100644
index 0000000000..e99daea2a9
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-202-t.svg
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="CL" desc="longest substring ligature matching" status="accepted"
+ approved="yes"
+ version="$Revision: 1.11 $" testname="$RCSfile: fonts-glyph-202-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test that ligatures are always used, and only used, when they occur before the
+ glyphs for characters they are ligatures of. The word "fjord" is displayed twice;
+ the lower one must use the fj ligature and the upper one must not; the top of the letter f overlaps the
+ dot of the letter j..
+ </p>
+ <p>
+ Two fonts are defined, almost identical; in one the fj ligature is
+ defined after "f" but before "j"; in the second one it is the last glyph.
+ This tests longest-substring matching.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-glyph-202-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font xml:id="Fjord-BoldOblique-jfirst" horiz-adv-x="312" >
+ <font-face
+ font-family="Fjord-jf"
+ font-weight="700"
+ font-style="oblique"
+ font-stretch="normal"
+ units-per-em="1000"
+ panose-1="2 0 8 3 0 0 0 0 0 0"
+ ascent="800"
+ descent="-200"
+ x-height="447"
+ cap-height="-1e+10"
+ bbox="-92 -234 639 726.333"
+ underline-thickness="50"
+ underline-position="-100"
+ slope="-9.8"
+ unicode-range="U+0064-U+0072"
+ />
+ <missing-glyph horiz-adv-x="432"
+ d="M33 0v666h333v-666h-333zM66 33h267v600h-267v-600z" />
+
+ <glyph glyph-name="j" unicode="j"
+ d="M248 644c4.66701 1.33301 11.333 1.33301 20 0c14 -3.33301 25 -10 33 -20c15.333 -18.667 17.667 -39.333 7 -62v-2v0c-4.66699 -8.66699 -10.667 -15.667 -18 -21c-6.66699 -4.66699 -14.667 -7.66699 -24 -9h-1c-22 -4.66699 -39.667 1.66699 -53 19l-1 1
+ c-15.333 19.333 -17.667 40.333 -7 63l1 1c3.33299 8 8.33299 14.333 15 19c8.66701 6 18 9.66699 28 11zM82 385l4 18l14 3l32 4l92 21l29 10l17 5l20 1l-59 -343l-12 -73c-8 -46 -18.333 -79.3333 -31 -100c-38.667 -66.667 -108 -116 -208 -148
+ c-24 -7.33299 -48 -13 -72 -17l3 20c19.3333 4 37.6667 10.333 55 19c55.3333 28 95 76.667 119 146l5 16c4.6667 15.3333 11.667 53 21 113l22 124l17 103l5 28c1.33299 12 1.66701 19.667 1 23c-8 25.333 -32 34.333 -72 27h-2z" />
+ <glyph glyph-name="fjlig" unicode="fj" horiz-adv-x="624"
+ d="M639 633v-23c-5.33331 -25.3333 -20.3333 -41.6667 -45 -49c-18.6667 -6 -36.3333 -4.33331 -53 5c-8.66669 4.66669 -15 10 -19 16c-6 6.66669 -10 15 -12 25c-2 11.3333 -2.33334 21 -1 29c2 9.33331 6.66669 19 14 29c-26.6667 14 -45.6667 22.3333 -57 25
+ c-10 2.66669 -17.6667 3.66669 -23 3c-4.66666 0 -12.3333 -3 -23 -9c-15.3333 -8.66669 -30.6667 -20.3333 -46 -35c-33.3333 -33.3333 -56 -71 -68 -113l-9 -45l-10 -62h312l-23 -137l-34 -201l-11 -64l-9 -46c-4 -12.6667 -11.6667 -26.3333 -23 -41l-1 -2
+ c-17.3333 -22 -45 -44 -83 -66l-102 -57c-15.3333 -10 -29 -20.3333 -41 -31h-1c-5.33334 5.33333 -8.33334 9.66667 -9 13v1c0 1.33333 2.33334 4.33333 7 9l22 19c40.6667 36.6667 69.6667 69 87 97c12 19.3333 20.3333 36 25 50c4 12.6667 8 32.3333 12 59l13 76l35 203
+ l15 90h-196l-15 -87l-24 -142l-13 -77l-6 -34v-4c1.33333 -17.3333 15 -28.6667 41 -34l12 -2l-3 -20h-236l3 20c27.3333 0 47.6667 9.66667 61 29l4 6l5 22l6 38l49 285h-60l6 17l4 9l16 2h39c7.33333 62.6667 21.6667 113 43 151c12.6667 21.3333 25.6667 39.3333 39 54
+ c54.6667 58.6667 130 89.3333 226 92c13.3333 0.666687 27 0.333313 41 -1c34 -2 64.6667 -10.3333 92 -25c10 -4 17.6667 -16.6667 23 -38c2.66669 -9.33331 4 -19 4 -29z" />
+ <glyph glyph-name="f" unicode="f"
+ d="M171 429c3.33299 25.333 7.66701 48.333 13 69l11 46c20.667 62.667 53 109 97 139c8.66699 6.66699 21.667 13.667 39 21c28.667 12 62.333 19 101 21c33.333 2 62 -0.666992 86 -8h1c16 -5.33301 30 -12.667 42 -22c6.66699 -4 11.333 -8.66699 14 -14
+ c1.33301 -2 1.66699 -9 1 -21v-1l-2 -48c-2.66699 -10.667 -6 -19 -10 -25c-15.333 -22.667 -37 -32 -65 -28c-12 2 -22.333 6.33301 -31 13c-6.66699 5.33301 -12 11.667 -16 19c-9.33301 15.333 -11.333 32.333 -6 51c1.33301 4.66699 3.33301 9.66699 6 15l3 10
+ c-0.666992 2.66699 -3.66699 5.66699 -9 9c-6.66699 5.33301 -14.667 9.66699 -24 13l-11 3c-3.33301 0 -9.66699 -3.66699 -19 -11c-12.667 -9.33301 -25.333 -22.667 -38 -40c-22.667 -31.333 -39.333 -67.667 -50 -109l-6 -38l-11 -64h116l-6 -18l-5 -8l-10 -2h-20h-80
+ l-14 -83l-27 -157l-12 -70l-5 -33v-1c1.33299 -17.3333 15 -28.6667 41 -34l12 -2l-3 -20h-236l3 20c27.3333 0 47.6667 9.6667 61 29l4 6l5 22l6 38l49 285h-60l6 17l4 9l16 2h39z" />
+ <glyph glyph-name="o" unicode="o" horiz-adv-x="554"
+ d="M346 447c15.333 0.666992 32 0 50 -2c42 -3.33301 75.333 -16 100 -38c20.667 -16.667 36 -40.333 46 -71c15.333 -46 15.667 -95.333 1 -148l-2 -6c-20.667 -69.333 -58.333 -121.667 -113 -157l-22 -12c-29.333 -14.6667 -66 -24.3333 -110 -29
+ c-58 -4.6667 -105 2.6667 -141 22c-8 4 -17 10.3333 -27 19c-45.3333 41.3333 -62.6667 101 -52 179c2.6667 19.333 7.3333 38.333 14 57l20 44c34 65.333 84.333 108 151 128c19.333 5.33301 47.667 10 85 14zM341 416c-6 0 -14 -3.33301 -24 -10
+ c-21.333 -12 -39.333 -26.667 -54 -44c-46.667 -52.667 -71 -113 -73 -181c-0.667007 -25.333 2.33299 -49.667 9 -73c11.333 -35.3333 29.333 -61.6667 54 -79c15.333 -10 26 -15 32 -15c4.66699 0 13 3.3333 25 10c21.333 12 39.333 26.6667 54 44
+ c46.667 52 71 112.333 73 181c0.666992 24.667 -2 48.333 -8 71c-11.333 36 -29.667 63 -55 81c-12 9.33301 -23 14.333 -33 15z" />
+ <glyph glyph-name="r" unicode="r" horiz-adv-x="445"
+ d="M318 422c-1.33301 5.33301 2 9.66699 10 13c8.66699 4.66699 23.333 8.33301 44 11c67.333 9.33301 110 -2.66699 128 -36l7 -19c2 -9.33301 2.66699 -18 2 -26c-1.33301 -8.66699 -10 -15.667 -26 -21c-20 -5.33301 -39.667 -8 -59 -8c-11.333 0 -19.667 1 -25 3
+ c-5.33301 1.33301 -7.33301 8 -6 20v3c-1.33301 17.333 -7.33301 31.333 -18 42c-6 6 -11.333 9 -16 9c-4.66699 -0.666992 -12.333 -5.33301 -23 -14c-17.333 -14 -32.333 -33.333 -45 -58c-12.667 -25.333 -22.333 -50.333 -29 -75
+ c-4.66699 -16.667 -12.667 -58.333 -24 -125l-10 -56l-4 -28c1.33299 -17.3333 15 -28.6667 41 -34l12 -2l-3 -20h-236l3 20c26.6667 0 47 9.6667 61 29l2 4c1.333 1.3333 3.667 9.3333 7 24l7 43l26 149l10 60c2.66701 15.333 2.33299 26.333 -1 33
+ c-8 16 -24.667 24 -50 24l-21 -2l4 18l12 3h1l33 4c30 4.66699 60.333 11.667 91 21l30 10l17 5l20 1l-12 -72h1c8.66699 18.667 21.667 34 39 46v1zM278 375h-1h1z" />
+ <glyph glyph-name="d" unicode="d" horiz-adv-x="562"
+ d="M380 666l50 5l81 19l31 10l22 7l20 1l-10 -60l-21 -123l-58 -339l-15 -91l-4 -23c-1.33301 -10 -1.66699 -16.3333 -1 -19c5.33301 -19.3333 22 -30 50 -32h1h1l-3 -20h-147l1 86h-1c-3.33301 -11.3333 -9.66699 -23.3333 -19 -36c-18.667 -29.3333 -41 -49 -67 -59
+ c-11.333 -4 -26 -6.6667 -44 -8c-14 -1.3333 -28 -1.3333 -42 0c-37.333 3.3333 -66 14.6667 -86 34c-26 25.3333 -41 63.6667 -45 115c-6 72 11.3333 139.667 52 203l2 3c20 30.667 43.333 54 70 70c30 18 65 29.667 105 35c23.333 2.66699 41 0.333008 53 -7
+ c22 -14 30.667 -35.333 26 -64l-1 -6l-8 -19c-3.33301 -3.33301 -5.33301 -5 -6 -5l-8 4l-14 10c6.66699 10 10 18.333 10 25v1c0 16 -6.66699 26.667 -20 32c-5.33301 2 -11 2.33301 -17 1c-4 -0.666992 -11 -4.33301 -21 -11c-14 -10.667 -27.333 -23.667 -40 -39
+ c-39.333 -50 -61 -109 -65 -177c-2 -29.333 0 -55.667 6 -79c8.66701 -36.6667 24.333 -63 47 -79c13.333 -10 23.667 -14.6667 31 -14c6 0.6667 15 5.3333 27 14c13.333 10.6667 26.333 27 39 49c14 24 25 54.333 33 91l22 119l31 180l16 98l5 28l1 19
+ c-3.33301 19.333 -18.667 30.333 -46 33h-6l-21 -2z" />
+ </font>
+ <font xml:id="Fjord-BoldOblique-ffirst" horiz-adv-x="312" >
+ <font-face
+ font-family="Fjord-ff"
+ font-weight="700"
+ font-style="oblique"
+ font-stretch="normal"
+ units-per-em="1000"
+ panose-1="2 0 8 3 0 0 0 0 0 0"
+ ascent="800"
+ descent="-200"
+ x-height="447"
+ cap-height="-1e+10"
+ bbox="-92 -234 639 726.333"
+ underline-thickness="50"
+ underline-position="-100"
+ slope="-9.8"
+ unicode-range="U+0064-U+0072"
+ />
+ <missing-glyph horiz-adv-x="432"
+ d="M33 0v666h333v-666h-333zM66 33h267v600h-267v-600z" />
+ <glyph glyph-name="f" unicode="f"
+ d="M171 429c3.33299 25.333 7.66701 48.333 13 69l11 46c20.667 62.667 53 109 97 139c8.66699 6.66699 21.667 13.667 39 21c28.667 12 62.333 19 101 21c33.333 2 62 -0.666992 86 -8h1c16 -5.33301 30 -12.667 42 -22c6.66699 -4 11.333 -8.66699 14 -14
+ c1.33301 -2 1.66699 -9 1 -21v-1l-2 -48c-2.66699 -10.667 -6 -19 -10 -25c-15.333 -22.667 -37 -32 -65 -28c-12 2 -22.333 6.33301 -31 13c-6.66699 5.33301 -12 11.667 -16 19c-9.33301 15.333 -11.333 32.333 -6 51c1.33301 4.66699 3.33301 9.66699 6 15l3 10
+ c-0.666992 2.66699 -3.66699 5.66699 -9 9c-6.66699 5.33301 -14.667 9.66699 -24 13l-11 3c-3.33301 0 -9.66699 -3.66699 -19 -11c-12.667 -9.33301 -25.333 -22.667 -38 -40c-22.667 -31.333 -39.333 -67.667 -50 -109l-6 -38l-11 -64h116l-6 -18l-5 -8l-10 -2h-20h-80
+ l-14 -83l-27 -157l-12 -70l-5 -33v-1c1.33299 -17.3333 15 -28.6667 41 -34l12 -2l-3 -20h-236l3 20c27.3333 0 47.6667 9.6667 61 29l4 6l5 22l6 38l49 285h-60l6 17l4 9l16 2h39z" />
+ <glyph glyph-name="fjlig" unicode="fj" horiz-adv-x="624"
+ d="M639 633v-23c-5.33331 -25.3333 -20.3333 -41.6667 -45 -49c-18.6667 -6 -36.3333 -4.33331 -53 5c-8.66669 4.66669 -15 10 -19 16c-6 6.66669 -10 15 -12 25c-2 11.3333 -2.33334 21 -1 29c2 9.33331 6.66669 19 14 29c-26.6667 14 -45.6667 22.3333 -57 25
+ c-10 2.66669 -17.6667 3.66669 -23 3c-4.66666 0 -12.3333 -3 -23 -9c-15.3333 -8.66669 -30.6667 -20.3333 -46 -35c-33.3333 -33.3333 -56 -71 -68 -113l-9 -45l-10 -62h312l-23 -137l-34 -201l-11 -64l-9 -46c-4 -12.6667 -11.6667 -26.3333 -23 -41l-1 -2
+ c-17.3333 -22 -45 -44 -83 -66l-102 -57c-15.3333 -10 -29 -20.3333 -41 -31h-1c-5.33334 5.33333 -8.33334 9.66667 -9 13v1c0 1.33333 2.33334 4.33333 7 9l22 19c40.6667 36.6667 69.6667 69 87 97c12 19.3333 20.3333 36 25 50c4 12.6667 8 32.3333 12 59l13 76l35 203
+ l15 90h-196l-15 -87l-24 -142l-13 -77l-6 -34v-4c1.33333 -17.3333 15 -28.6667 41 -34l12 -2l-3 -20h-236l3 20c27.3333 0 47.6667 9.66667 61 29l4 6l5 22l6 38l49 285h-60l6 17l4 9l16 2h39c7.33333 62.6667 21.6667 113 43 151c12.6667 21.3333 25.6667 39.3333 39 54
+ c54.6667 58.6667 130 89.3333 226 92c13.3333 0.666687 27 0.333313 41 -1c34 -2 64.6667 -10.3333 92 -25c10 -4 17.6667 -16.6667 23 -38c2.66669 -9.33331 4 -19 4 -29z" />
+ <glyph glyph-name="j" unicode="j"
+ d="M248 644c4.66701 1.33301 11.333 1.33301 20 0c14 -3.33301 25 -10 33 -20c15.333 -18.667 17.667 -39.333 7 -62v-2v0c-4.66699 -8.66699 -10.667 -15.667 -18 -21c-6.66699 -4.66699 -14.667 -7.66699 -24 -9h-1c-22 -4.66699 -39.667 1.66699 -53 19l-1 1
+ c-15.333 19.333 -17.667 40.333 -7 63l1 1c3.33299 8 8.33299 14.333 15 19c8.66701 6 18 9.66699 28 11zM82 385l4 18l14 3l32 4l92 21l29 10l17 5l20 1l-59 -343l-12 -73c-8 -46 -18.333 -79.3333 -31 -100c-38.667 -66.667 -108 -116 -208 -148
+ c-24 -7.33299 -48 -13 -72 -17l3 20c19.3333 4 37.6667 10.333 55 19c55.3333 28 95 76.667 119 146l5 16c4.6667 15.3333 11.667 53 21 113l22 124l17 103l5 28c1.33299 12 1.66701 19.667 1 23c-8 25.333 -32 34.333 -72 27h-2z" />
+ <glyph glyph-name="o" unicode="o" horiz-adv-x="554"
+ d="M346 447c15.333 0.666992 32 0 50 -2c42 -3.33301 75.333 -16 100 -38c20.667 -16.667 36 -40.333 46 -71c15.333 -46 15.667 -95.333 1 -148l-2 -6c-20.667 -69.333 -58.333 -121.667 -113 -157l-22 -12c-29.333 -14.6667 -66 -24.3333 -110 -29
+ c-58 -4.6667 -105 2.6667 -141 22c-8 4 -17 10.3333 -27 19c-45.3333 41.3333 -62.6667 101 -52 179c2.6667 19.333 7.3333 38.333 14 57l20 44c34 65.333 84.333 108 151 128c19.333 5.33301 47.667 10 85 14zM341 416c-6 0 -14 -3.33301 -24 -10
+ c-21.333 -12 -39.333 -26.667 -54 -44c-46.667 -52.667 -71 -113 -73 -181c-0.667007 -25.333 2.33299 -49.667 9 -73c11.333 -35.3333 29.333 -61.6667 54 -79c15.333 -10 26 -15 32 -15c4.66699 0 13 3.3333 25 10c21.333 12 39.333 26.6667 54 44
+ c46.667 52 71 112.333 73 181c0.666992 24.667 -2 48.333 -8 71c-11.333 36 -29.667 63 -55 81c-12 9.33301 -23 14.333 -33 15z" />
+ <glyph glyph-name="r" unicode="r" horiz-adv-x="445"
+ d="M318 422c-1.33301 5.33301 2 9.66699 10 13c8.66699 4.66699 23.333 8.33301 44 11c67.333 9.33301 110 -2.66699 128 -36l7 -19c2 -9.33301 2.66699 -18 2 -26c-1.33301 -8.66699 -10 -15.667 -26 -21c-20 -5.33301 -39.667 -8 -59 -8c-11.333 0 -19.667 1 -25 3
+ c-5.33301 1.33301 -7.33301 8 -6 20v3c-1.33301 17.333 -7.33301 31.333 -18 42c-6 6 -11.333 9 -16 9c-4.66699 -0.666992 -12.333 -5.33301 -23 -14c-17.333 -14 -32.333 -33.333 -45 -58c-12.667 -25.333 -22.333 -50.333 -29 -75
+ c-4.66699 -16.667 -12.667 -58.333 -24 -125l-10 -56l-4 -28c1.33299 -17.3333 15 -28.6667 41 -34l12 -2l-3 -20h-236l3 20c26.6667 0 47 9.6667 61 29l2 4c1.333 1.3333 3.667 9.3333 7 24l7 43l26 149l10 60c2.66701 15.333 2.33299 26.333 -1 33
+ c-8 16 -24.667 24 -50 24l-21 -2l4 18l12 3h1l33 4c30 4.66699 60.333 11.667 91 21l30 10l17 5l20 1l-12 -72h1c8.66699 18.667 21.667 34 39 46v1zM278 375h-1h1z" />
+ <glyph glyph-name="d" unicode="d" horiz-adv-x="562"
+ d="M380 666l50 5l81 19l31 10l22 7l20 1l-10 -60l-21 -123l-58 -339l-15 -91l-4 -23c-1.33301 -10 -1.66699 -16.3333 -1 -19c5.33301 -19.3333 22 -30 50 -32h1h1l-3 -20h-147l1 86h-1c-3.33301 -11.3333 -9.66699 -23.3333 -19 -36c-18.667 -29.3333 -41 -49 -67 -59
+ c-11.333 -4 -26 -6.6667 -44 -8c-14 -1.3333 -28 -1.3333 -42 0c-37.333 3.3333 -66 14.6667 -86 34c-26 25.3333 -41 63.6667 -45 115c-6 72 11.3333 139.667 52 203l2 3c20 30.667 43.333 54 70 70c30 18 65 29.667 105 35c23.333 2.66699 41 0.333008 53 -7
+ c22 -14 30.667 -35.333 26 -64l-1 -6l-8 -19c-3.33301 -3.33301 -5.33301 -5 -6 -5l-8 4l-14 10c6.66699 10 10 18.333 10 25v1c0 16 -6.66699 26.667 -20 32c-5.33301 2 -11 2.33301 -17 1c-4 -0.666992 -11 -4.33301 -21 -11c-14 -10.667 -27.333 -23.667 -40 -39
+ c-39.333 -50 -61 -109 -65 -177c-2 -29.333 0 -55.667 6 -79c8.66701 -36.6667 24.333 -63 47 -79c13.333 -10 23.667 -14.6667 31 -14c6 0.6667 15 5.3333 27 14c13.333 10.6667 26.333 27 39 49c14 24 25 54.333 33 91l22 119l31 180l16 98l5 28l1 19
+ c-3.33301 19.333 -18.667 30.333 -46 33h-6l-21 -2z" />
+ </font>
+ </defs>
+ <g fill="#052" fill-opacity="0.4" stroke="#fff" stroke-width="0.5">
+ <text x="160" y="260" font-family="Fjord-jf" font-weight="700" font-style="oblique"
+ font-size="120">fjord</text>
+ <text x="160" y="130" font-family="Fjord-ff" font-weight="700" font-style="oblique"
+ font-size="120">fjord</text>
+ <g font-size="14" fill-opacity="0.8" stroke="none">
+ <text x="20" y="100">The Fjord fonts</text>
+ <text x="20" y="120" >are derived from</text>
+ <text x="20" y="140">Gladiator</text>
+ <text x="20" y="160">by Bert Bos</text>
+ <text x="20" y="180">and are used</text>
+ <text x="20" y="200">by kind permission.</text>
+ </g>
+ <!-- No norwegian blue parrots were harmed n the making of this test -->
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.11 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-203-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-203-t.svg
new file mode 100644
index 0000000000..ec64542f2d
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-glyph-203-t.svg
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ATE, CM" owner="CL" desc="test path commands in glyphs" status="accepted"
+ approved="yes"
+ version="$Revision: 1.3 $" testname="$RCSfile: fonts-glyph-203-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/"
+ xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test that all of the SVG path commands are accepted for defining glyphs. The upper,
+ black text must be a reflection of the lower, colored glyph shapes.
+ </p>
+ <p>
+ The letter A uses L commands, the letter H uses H and V commands, and
+ the letter B uses cubic beziers. The letter C uses a mix of quadratic beziers and vertical lines.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-glyph-203-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <defs>
+ <font xml:id="curvy" horiz-adv-x="450">
+ <font-face font-family="SVGPath" font-weight="500" units-per-em="1000" ascent="800"
+ descent="-200"/>
+ <missing-glyph/>
+ <glyph unicode="A" d="M0,0 L100,600 L300,600 L400,0 L300,0 L 200,200 L 100,0 z
+ M 100,200 L300,200 L 200,500 z"/>
+ <glyph unicode="B" horiz-adv-x="350"
+ d="M0,0 c0,200 0,400 0,600 c33,0 66,0 100,0 c 300,0 300,-300 0,-300
+ c 300,0 300,-300 0,-300 z
+ M 100,100 c 140,0 140,100, 0,100 z
+ M 100,400 c 140,0 140,100, 0,100 z"/>
+ <glyph unicode="C" d="M100,100 Q 0,300 100,500 Q 250,600 400,500
+ v-100 Q300,450 200,400 Q 150,300 200,200 Q 300,150 400,200
+ v-100 Q250,0 100,100 z" />
+ <glyph unicode="H"
+ d="M0,0 v600 h100 v-250 h200 v250 h100 v-600 h-100 v250 h-200 v-250 z"/>
+ </font>
+ </defs>
+ <text x="50" y="150" font-family="SVGPath" font-size="150">BACH</text>
+ <g transform="translate (50,160)">
+ <g transform="scale(0.15)" fill="green">
+ <path
+ d="M0,0 c0,200 0,400 0,600 c33,0 66,0 100,0 c 300,0 300,-300 0,-300
+ c 300,0 300,-300 0,-300 z
+ M 100,100 c 140,0 140,100, 0,100 z
+ M 100,400 c 140,0 140,100, 0,100 z"
+ />
+ </g>
+ </g>
+ <g transform="translate (102.5,160)">
+ <g transform="scale(0.15)" fill="blue">
+ <path d="M0,0 L100,600 L300,600 L400,0 L300,0 L 200,200 L 100,0 z
+ M 100,200 L300,200 L 200,500 z"/>
+ </g>
+ </g>
+ <g transform="translate (170,160)">
+ <g transform="scale(0.15)" fill="maroon">
+ <path d="M100,100 Q 0,300 100,500 Q 250,600 400,500
+ v-100 Q300,450 200,400 Q 150,300 200,200 Q 300,150 400,200
+ v-100 Q250,0 100,100 z"/>
+ </g>
+ </g>
+ <g transform="translate (237.5,160)">
+ <g transform="scale(0.15)" fill="rgb(153, 50, 204)">
+ <path d="M0,0 v600 h100 v-250 h200 v250 h100 v-600 h-100 v250 h-200 v-250 z"/>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.3 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-kern-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-kern-01-t.svg
new file mode 100644
index 0000000000..84fa4574e9
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-kern-01-t.svg
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN" owner="VH" desc="Test handling of hkern elements in SVG Fonts" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: fonts-kern-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test validates handling of the hkern element.</p>
+ <p>In all instances, a text element matching a font with hkern is displayed along with reference markers showing the expected glyph positioning.</p>
+ <p>The 'fontA' cell shows the string "12" with "fontA" for which there in a kerning pair defined with u1="1" and u2="2".</p>
+ <p>The 'fontB' cell shows the string "12" with "fontB" for which there in a kerning pair defined with g1="gl_1" and g2="gl_2", where "gl_1" has unicode="1" and "gl_2" has unicode="2".</p>
+ <p>The 'fontC' cell shows the string "1234" with "fontC" were the same kerning pair uses u1/u2 to match "12" and g1/g2 to match "34".</p>
+ <p>The 'fontD' cell shows the string "1234" with "fontD" were the same kerning pair uses u1/u2 to match "12" and "34" (u1/u2 are lists of character vales).</p>
+ <p>The 'fontE' cell shows the string "1234" with "fontE" were the same kerning pair uses g1/g2 to match "12" and "34" (g1/g2 are lists of names).</p>
+ <p>The 'fontF' cell shows the string "1234" with "fontF" were the same kerning pair uses u1/u2 to match "12" and "34" (u1/u2 are unicode ranges).</p>
+ <p>The 'fontG' cell shows the string "12" with "fontG" were for which there is a kerning pair with u1 matching "1" and g2 matching "gl_2".</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-kern-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font horiz-adv-x="224">
+ <font-face font-family="fontG" units-per-em="1000" ascent="917" descent="-250" />
+ <missing-glyph horiz-adv-x="800" d="M 0 0 L 750 0 L 750 1000 L 0 1000 Z" />
+ <glyph unicode="1" glyph-name="gl_1" horiz-adv-x="250" d="M 0 0 L 250 0 L 250 250 L 0 250 Z" />
+ <glyph unicode="2" glyph-name="gl_2" horiz-adv-x="1500" d="M 0 0 L 500 0 L 500 500 L 0 500 Z" />
+ <hkern u1="1" g2="gl_2" k="-1000" />
+ </font>
+ <font horiz-adv-x="224">
+ <font-face font-family="fontF" units-per-em="1000" ascent="917" descent="-250" />
+ <missing-glyph horiz-adv-x="800" d="M 0 0 L 750 0 L 750 1000 L 0 1000 Z" />
+ <glyph unicode="1" glyph-name="gl_1" horiz-adv-x="250" d="M 0 0 L 250 0 L 250 250 L 0 250 Z" />
+ <glyph unicode="2" glyph-name="gl_2" horiz-adv-x="1500" d="M 0 0 L 500 0 L 500 500 L 0 500 Z" />
+ <glyph unicode="3" glyph-name="gl_3" horiz-adv-x="750" d="M 0 0 L 750 0 L 750 750 L 0 750 Z" />
+ <glyph unicode="4" glyph-name="gl_4" horiz-adv-x="1000" d="M 0 0 L 1000 0 L 1000 1000 L 0 1000 Z" />
+ <!-- u1 covers '0' to '9' and ':' ';' '<' '=' '>' '?' -->
+ <!-- u2 covers '1' '2' '3' and '4' -->
+ <!-- So, this is a match for '12', '23' and '34' -->
+ <hkern u1="U+003?" u2="U+0031-0034" k="-1500" />
+ </font>
+ <font horiz-adv-x="224">
+ <font-face font-family="fontE" units-per-em="1000" ascent="917" descent="-250" />
+ <missing-glyph horiz-adv-x="800" d="M 0 0 L 750 0 L 750 1000 L 0 1000 Z" />
+ <glyph unicode="1" glyph-name="gl_1" horiz-adv-x="250" d="M 0 0 L 250 0 L 250 250 L 0 250 Z" />
+ <glyph unicode="2" glyph-name="gl_2" horiz-adv-x="1500" d="M 0 0 L 500 0 L 500 500 L 0 500 Z" />
+ <glyph unicode="3" glyph-name="gl_3" horiz-adv-x="750" d="M 0 0 L 750 0 L 750 750 L 0 750 Z" />
+ <glyph unicode="4" glyph-name="gl_4" horiz-adv-x="1000" d="M 0 0 L 1000 0 L 1000 1000 L 0 1000 Z" />
+ <hkern g1="gl_1,gl_3" g2="gl_2,gl_4" k="-1500" />
+ </font>
+ <font horiz-adv-x="224">
+ <font-face font-family="fontD" units-per-em="1000" ascent="917" descent="-250" />
+ <missing-glyph horiz-adv-x="800" d="M 0 0 L 750 0 L 750 1000 L 0 1000 Z" />
+ <glyph unicode="1" glyph-name="gl_1" horiz-adv-x="250" d="M 0 0 L 250 0 L 250 250 L 0 250 Z" />
+ <glyph unicode="2" glyph-name="gl_2" horiz-adv-x="1500" d="M 0 0 L 500 0 L 500 500 L 0 500 Z" />
+ <glyph unicode="3" glyph-name="gl_3" horiz-adv-x="750" d="M 0 0 L 750 0 L 750 750 L 0 750 Z" />
+ <glyph unicode="4" glyph-name="gl_4" horiz-adv-x="1000" d="M 0 0 L 1000 0 L 1000 1000 L 0 1000 Z" />
+ <hkern u1="1,3" u2="2,4" k="-1500" />
+ </font>
+ <font horiz-adv-x="224">
+ <font-face font-family="fontC" units-per-em="1000" ascent="917" descent="-250" />
+ <missing-glyph horiz-adv-x="800" d="M 0 0 L 750 0 L 750 1000 L 0 1000 Z" />
+ <glyph unicode="1" glyph-name="gl_1" horiz-adv-x="250" d="M 0 0 L 250 0 L 250 250 L 0 250 Z" />
+ <glyph unicode="2" glyph-name="gl_2" horiz-adv-x="1500" d="M 0 0 L 500 0 L 500 500 L 0 500 Z" />
+ <glyph unicode="3" glyph-name="gl_3" horiz-adv-x="750" d="M 0 0 L 750 0 L 750 750 L 0 750 Z" />
+ <glyph unicode="4" glyph-name="gl_4" horiz-adv-x="1000" d="M 0 0 L 1000 0 L 1000 1000 L 0 1000 Z" />
+ <hkern u1="1" u2="2" g1="gl_3" g2="gl_4" k="-1500" />
+ </font>
+ <font horiz-adv-x="224">
+ <font-face font-family="fontB" units-per-em="1000" ascent="917" descent="-250" />
+ <missing-glyph horiz-adv-x="800" d="M 0 0 L 750 0 L 750 1000 L 0 1000 Z" />
+ <glyph unicode="1" glyph-name="gl_1" horiz-adv-x="250" d="M 0 0 L 250 0 L 250 250 L 0 250 Z" />
+ <glyph unicode="2" glyph-name="gl_2" horiz-adv-x="500" d="M 0 0 L 500 0 L 500 500 L 0 500 Z" />
+ <hkern g1="gl_1" g2="gl_2" k="-2000" />
+ </font>
+ <font horiz-adv-x="224">
+ <font-face font-family="fontA" units-per-em="1000" ascent="917" descent="-250" />
+ <missing-glyph horiz-adv-x="800" d="M 0 0 L 750 0 L 750 1000 L 0 1000 Z" />
+ <glyph unicode="1" glyph-name="gl_1" horiz-adv-x="250" d="M 0 0 L 250 0 L 250 250 L 0 250 Z" />
+ <glyph unicode="2" glyph-name="gl_2" horiz-adv-x="500" d="M 0 0 L 500 0 L 500 500 L 0 500 Z" />
+ <hkern u1="1" u2="2" k="-1000" />
+ </font>
+ </defs>
+ <defs>
+ <g xml:id="marker">
+ <!-- <rect x="0" y="-10" width="10" height="10" /> -->
+ <line y2="-12" stroke="red" stroke-width="1" />
+ <line x2="12" stroke="red" stroke-width="1" />
+ <rect x="-2" y="-2" width="4" height="4" fill="red" />
+ </g>
+ <g xml:id="sampleBkg">
+ <rect width="200" height="20" fill="#eeeeee" />
+ <rect y="20" width="200" height="30" fill="#cccccc" />
+ <rect width="200" height="50" fill="none" stroke="black" />
+ </g>
+ </defs>
+ <text x="240" y="30" font-size="20" text-anchor="middle">&lt;hkern&gt;</text>
+ <g xml:id="legend" transform="translate(30, 60)">
+ <g>
+ <g>
+ <rect x="-20" width="20" height="50" fill="none" stroke="black" />
+ <text transform="translate(-5, 25) rotate(-90)" text-anchor="middle">font A</text>
+ </g>
+ <use xlink:href="#sampleBkg" />
+ <text x="5" y="15" font-size="12">u1="1" u2="2"</text>
+ <g transform="translate(5, 45) scale(2)" font-size="10">
+ <!-- Advance for '1': 0 -->
+ <use xlink:href="#marker" fill="#8888ff" />
+ <!-- Advance for '2' : '1'.advance + kerning -->
+ <!-- : ((250 - (-1000))/1000)*10 -->
+ <!-- : 12.5 -->
+ <use xlink:href="#marker" x="12.5" fill="#8888ff" />
+ <text font-family="fontA" font-size="10">12</text>
+ </g>
+ </g>
+ <g transform="translate(0, 55)">
+ <g>
+ <rect x="-20" width="20" height="50" fill="none" stroke="black" />
+ <text transform="translate(-5, 25) rotate(-90)" text-anchor="middle">font B</text>
+ </g>
+ <use xlink:href="#sampleBkg" />
+ <text x="5" y="15" font-size="12">g1="gl_1" g2="gl_2"</text>
+ <g transform="translate(5, 45) scale(2)">
+ <use xlink:href="#marker" fill="#8888ff" />
+ <use xlink:href="#marker" x="22.5" fill="#8888ff" />
+ <text font-family="fontB" font-size="10">12</text>
+ </g>
+ </g>
+ <g transform="translate(0, 110)">
+ <g>
+ <rect x="-20" width="20" height="50" fill="none" stroke="black" />
+ <text transform="translate(-5, 25) rotate(-90)" text-anchor="middle">font C</text>
+ </g>
+ <use xlink:href="#sampleBkg" />
+ <text x="5" y="15" font-size="12">u1="1" u2="2" g1="gl_3" g2="gl_4"</text>
+ <g transform="translate(5, 45) scale(2)">
+ <use xlink:href="#marker" fill="#8888ff" />
+ <!-- ((1.adv + '12'.k)/unitsPerEm)*fontSize -->
+ <use xlink:href="#marker" x="17.5" fill="#8888ff" />
+ <use xlink:href="#marker" x="32.5" fill="#8888ff" />
+ <!-- ((3.adv + '34'.k)/unitsPerEm)*fontSize -->
+ <use xlink:href="#marker" x="55" fill="#8888ff" />
+ <text font-family="fontC" font-size="10">1234</text>
+ </g>
+ </g>
+ <g transform="translate(0, 165)">
+ <g>
+ <rect x="-20" width="20" height="50" fill="none" stroke="black" />
+ <text transform="translate(-5, 25) rotate(-90)" text-anchor="middle">font D</text>
+ </g>
+ <use xlink:href="#sampleBkg" />
+ <text x="5" y="15" font-size="12">u1="1,3" u2="2,4"</text>
+ <g transform="translate(5, 45) scale(2)">
+ <use xlink:href="#marker" fill="#8888ff" />
+ <use xlink:href="#marker" x="17.5" fill="#8888ff" />
+ <use xlink:href="#marker" x="32.5" fill="#8888ff" />
+ <use xlink:href="#marker" x="55" fill="#8888ff" />
+ <text font-family="fontD" font-size="10">1234</text>
+ </g>
+ </g>
+ <g transform="translate(240, 0)">
+ <g>
+ <rect x="-20" width="20" height="50" fill="none" stroke="black" />
+ <text transform="translate(-5, 25) rotate(-90)" text-anchor="middle">font E</text>
+ </g>
+ <use xlink:href="#sampleBkg" />
+ <text x="5" y="15" font-size="12">g1="gl_1,gl_3" g2="gl_2,gl_4"</text>
+ <g transform="translate(5, 45) scale(2)">
+ <use xlink:href="#marker" fill="#8888ff" />
+ <use xlink:href="#marker" x="17.5" fill="#8888ff" />
+ <use xlink:href="#marker" x="32.5" fill="#8888ff" />
+ <use xlink:href="#marker" x="55" fill="#8888ff" />
+ <text font-family="fontE" font-size="10">1234</text>
+ </g>
+ </g>
+ <g transform="translate(240, 55)">
+ <g>
+ <rect x="-20" width="20" height="50" fill="none" stroke="black" />
+ <text transform="translate(-5, 25) rotate(-90)" text-anchor="middle">font F</text>
+ </g>
+ <use xlink:href="#sampleBkg" />
+ <text x="5" y="15" font-size="12">u1="U+003?" u2="U+0031-34"</text>
+ <g transform="translate(5, 45) scale(2)">
+ <use xlink:href="#marker" fill="#8888ff" />
+ <!-- '2' -->
+ <use xlink:href="#marker" x="17.5" fill="#8888ff" />
+ <!-- '3' -->
+ <use xlink:href="#marker" x="47.5" fill="#8888ff" />
+ <!-- '4' -->
+ <use xlink:href="#marker" x="70" fill="#8888ff" />
+ <text font-family="fontF" font-size="10">1234</text>
+ </g>
+ </g>
+ <g transform="translate(240, 110)">
+ <g>
+ <rect x="-20" width="20" height="50" fill="none" stroke="black" />
+ <text transform="translate(-5, 25) rotate(-90)" text-anchor="middle">font G</text>
+ </g>
+ <use xlink:href="#sampleBkg" />
+ <text x="5" y="15" font-size="12">u1="1" g2="gl_2"</text>
+ <g transform="translate(5, 45) scale(2)">
+ <!-- Advance for '1': 0 -->
+ <use xlink:href="#marker" fill="#8888ff" />
+ <!-- Advance for '2' : '1'.advance + kerning -->
+ <!-- : ((250 - (-1000))/1000)*10 -->
+ <!-- : 12.5 -->
+ <use xlink:href="#marker" x="12.5" fill="#8888ff" />
+ <text font-family="fontG" font-size="10">12</text>
+ </g>
+ </g>
+ </g>
+ <g xml:id="testContent" transform="translate(320, 100)" font-size="10"> </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-overview-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-overview-201-t.svg
new file mode 100644
index 0000000000..cd20c1f958
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/fonts-overview-201-t.svg
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="CL" desc="units-per-em values" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: fonts-overview-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This tests a range of values for the 'units per em' attribute. The
+ test is passed if the three letter β are all the same size.
+ </p>
+ <p>
+ The same glyph is defined three times in three fonts, but with different values
+ for units-per-em - 1,000, 10, and 10,000 - and with the other numerical values
+ that depend on units-per-em scaled accordingly. Text using these fonts must all be displayed at the same size,
+ because the same font-size is used throughout.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: fonts-overview-201-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font xml:id="beta" horiz-adv-x="550" >
+ <font-face
+ font-family="SVGbeta1"
+ font-weight="500"
+ units-per-em="1000"
+ ascent="800"
+ descent="-200"
+ unicode-range="U+03B2"
+ />
+ <missing-glyph />
+ <glyph glyph-name="beta" unicode="&#x3b2;"
+ d="M522.35 177.05c0 -103.55 -73.73 -201.4 -190.89 -201.4c-62.62 0 -123.22 22.7998 -138.37 85.5h-2.01999v-261.15h-135.34v573.7c0 136.8 37.3691 304.95 218.16 304.95c95.95 0 198.97 -40.85 198.97 -145.35c0 -94.05 -72.72 -133 -160.59 -152v-1.89999
+ c126.25 -16.15 210.08 -76 210.08 -202.35zM360.75 128.6v80.75c0 41.8 -3.03 149.15 -67.67 149.15c-15.15 0 -29.29 -8.54999 -44.44 -8.54999c-14.14 0 -20.2 18.05 -20.2 28.5c0 11.4 9.09 24.7 22.22 24.7c12.12 0 24.24 -6.64999 36.36 -6.64999
+ c45.45 0 45.45 79.8 45.45 108.3c0 42.75 2.01999 146.3 -63.63 146.3c-75.75 0 -77.77 -138.7 -77.77 -188.1v-394.25h31.31c3.03 -23.75 29.29 -49.4004 55.55 -49.4004c68.68 0 82.82 56.0508 82.82 109.25z" />
+ </font>
+ <font xml:id="beta2" horiz-adv-x="5.50" >
+ <font-face
+ font-family="SVGbeta2"
+ font-weight="500"
+ units-per-em="10"
+ ascent="8"
+ descent="-2"
+ unicode-range="U+03B2"
+ />
+ <missing-glyph />
+ <glyph glyph-name="beta" unicode="&#x3b2;"
+ d="M5.2235 1.7705c0 -1.0355 -0.7373 -2.014 -1.9089 -2.014c-0.6262 0 -1.2322 0.227998 -1.3837 0.855h-0.0201999v-2.6115h-1.3534v5.737c0 1.368 0.373691 3.0495 2.1816 3.0495c0.9595 0 1.9897 -0.4085 1.9897 -1.4535c0 -0.9405 -0.7272 -1.33 -1.6059 -1.52v-0.0189999
+ c1.2625 -0.1615 2.1008 -0.76 2.1008 -2.0235zM3.6075 1.286v0.8075c0 0.418 -0.0303 1.4915 -0.6767 1.4915c-0.1515 0 -0.2929 -0.0854999 -0.4444 -0.0854999c-0.1414 0 -0.202 0.1805 -0.202 0.285c0 0.114 0.0909 0.247 0.2222 0.247c0.1212 0 0.2424 -0.0664999 0.3636 -0.0664999
+ c0.4545 0 0.4545 0.798 0.4545 1.083c0 0.4275 0.0201999 1.463 -0.6363 1.463c-0.7575 0 -0.7777 -1.387 -0.7777 -1.881v-3.9425h0.3131c0.0303 -0.2375 0.2929 -0.494004 0.5555 -0.494004c0.6868 0 0.8282 0.560508 0.8282 1.0925z" />
+ </font>
+ <font xml:id="beta3" horiz-adv-x="55000" >
+ <font-face
+ font-family="SVGbeta3"
+ font-weight="500"
+ units-per-em="10000"
+ ascent="8000"
+ descent="-2000"
+ unicode-range="U+03B2"
+ />
+ <missing-glyph />
+ <glyph glyph-name="beta" unicode="&#x3b2;"
+ d="M5223.5 1770.5c0 -1035.5 -737.3 -2014.0 -1908.9 -2014.0c-626.2 0 -1232.2 227.998 -1383.7 855.0h-20.1999v-2611.5h-1353.4v5737.0c0 1368.0 373.691 3049.5 2181.6 3049.5c959.5 0 1989.7 -408.5 1989.7 -1453.5c0 -940.5 -727.2 -1330.0 -1605.9 -1520.0v-18.9999
+ c1262.5 -161.5 2100.8 -760.0 2100.8 -2023.5zM3607.5 1286.0v807.5c0 418.0 -30.3 1491.5 -676.7 1491.5c-151.5 0 -292.9 -85.4999 -444.4 -85.4999c-141.4 0 -202.0 180.5 -202.0 285.0c0 114.0 90.9 247.0 222.2 247.0c121.2 0 242.4 -66.4999 363.6 -66.4999
+ c454.5 0 454.5 798.0 454.5 1083.0c0 427.5 20.1999 1463.0 -636.3 1463.0c-757.5 0 -777.7 -1387.0 -777.7 -1881.0v-3942.5h313.1c30.3 -237.5 292.9 -494.004 555.5 -494.004c686.8 0 828.2 560.508 828.2 1092.5z" />
+ </font>
+ </defs>
+ <!-- alphabetic baseline -->
+ <path stroke-width="2" stroke="#888" d="M 50,200 H 420"/>
+ <!-- ascent -->
+ <path stroke-width="2" stroke="#888" d="M 50, 56 H 420"/>
+ <!-- descent -->
+ <path stroke-width="2" stroke="#888" d="M 50, 236 H 420"/>
+
+ <text x="50" y="200" font-family="SVGbeta1" font-size="180">β</text>
+ <text x="180" y="200" font-family="SVGbeta2" font-size="180">β</text>
+ <text x="310" y="200" font-family="SVGbeta3" font-size="180">β</text>
+
+ <text x="60" y="260" font-size="10">1,000</text>
+ <text x="190" y="260" font-size="10">10</text>
+ <text x="320" y="260" font-size="10">10,000</text>
+ <text x="110" y="280" font-size="16">varying units-per-em values</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/intro-compat-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/intro-compat-201-t.svg
new file mode 100644
index 0000000000..9ebfa42eeb
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/intro-compat-201-t.svg
Binary files differ
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-201-t.svg
new file mode 100644
index 0000000000..c542ad48f8
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-201-t.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="CL" desc="baseline JPEG test" status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: jpeg-required-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test RGB baseline JPEG with the most common chrominance subsampling, 4:1:1.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: jpeg-required-201-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <image x="10" y="10" width="300" height="300" xlink:href="../images/cloud411q75s.jpg"/>
+ <text x="320" y="100">baseline 4:1:1</text>
+ <text x="320" y="130">sequential</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-202-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-202-t.svg
new file mode 100644
index 0000000000..2e73414cbe
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-202-t.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="CL" desc="baseline JPEG test" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: jpeg-required-202-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test RGB optimised baseline JPEG with the most common chrominance subsampling, 4:1:1.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: jpeg-required-202-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <image x="10" y="10" width="300" height="300" xlink:href="../images/cloud411q75o.jpg"/>
+ <text x="320" y="100">optimized 4:1:1</text>
+ <text x="320" y="130">sequential</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-203-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-203-t.svg
new file mode 100644
index 0000000000..a11f8a06f0
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-203-t.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="CL" desc="baseline JPEG test" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: jpeg-required-203-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test progressive, RGB optimised JPEG with the most common chrominance subsampling, 4:1:1.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: jpeg-required-203-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <image x="10" y="10" width="300" height="300" xlink:href="../images/cloud411q75p.jpg"/>
+ <text x="320" y="100">optimized 4:1:1</text>
+ <text x="320" y="130">progressive</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-204-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-204-t.svg
new file mode 100644
index 0000000000..64be72e88d
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-204-t.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="CL" desc="baseline JPEG test" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: jpeg-required-204-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test greyscale baseline JPEG.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: jpeg-required-204-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <image x="10" y="10" width="300" height="300" xlink:href="../images/cloudgsq75s.jpg"/>
+ <text x="320" y="100">greyscale</text>
+ <text x="320" y="130">sequential</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-205-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-205-t.svg
new file mode 100644
index 0000000000..f9597150b1
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-205-t.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="CL" desc="baseline JPEG test" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: jpeg-required-205-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test RGB optimised baseline JPEG with the most common chrominance subsampling, 4:1:1 and with multiple APP markers.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: jpeg-required-205-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <image x="10" y="10" width="300" height="300" xlink:href="../images/cloud-ps411q4app.jpg"/>
+ <text x="320" y="100">optimised 4:1:1</text>
+ <text x="320" y="130">sequential</text>
+ <text x="320" y="160">multi APP markers</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-206-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-206-t.svg
new file mode 100644
index 0000000000..03f144e40a
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-206-t.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="CL" desc="baseline JPEG test" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: jpeg-required-206-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test RGB optimised JPEG with the most common chrominance subsampling, 4:1:1 and with a float DCT.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: jpeg-required-206-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <image x="10" y="10" width="300" height="300" xlink:href="../images/cloud411q65float.jpg"/>
+ <text x="320" y="100">optimised 4:1:1</text>
+ <text x="320" y="130">sequential</text>
+ <text x="320" y="160">float DCT</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-207-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-207-t.svg
new file mode 100644
index 0000000000..b9911a2d8e
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-207-t.svg
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="CL" desc="baseline JPEG test" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: jpeg-required-207-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test RGB optimised JPEG with no chrominance subsampling, 4:4:4.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: jpeg-required-207-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <image x="10" y="10" width="300" height="300" xlink:href="../images/cloud444q65o.jpg"/>
+ <text x="320" y="100">optimised 4:4:4</text>
+ <text x="320" y="130">sequential</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-208-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-208-t.svg
new file mode 100644
index 0000000000..97d4c76cc9
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-208-t.svg
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="CL" desc="baseline JPEG test" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: jpeg-required-208-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test RGB optimised JPEG with very unusual chrominance subsampling:
+ 2x2, 4x1, 1x2.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: jpeg-required-208-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <image x="10" y="10" width="300" height="300" xlink:href="../images/cloudoddq65o.jpg"/>
+ <text x="320" y="100">optimised 4:4:2</text>
+ <text x="320" y="130">sequential</text>
+ <text x="320" y="160" font-size="12">unusual subsampling</text>
+ <text x="320" y="180" font-size="12">2x2, 4x1, 1x2</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-209-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-209-t.svg
new file mode 100644
index 0000000000..f2bfd07be6
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/jpeg-required-209-t.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="CL" desc="baseline JPEG test" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: jpeg-required-209-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test RGB baseline JPEG with the most common chrominance subsampling, 4:1:1 and high compression level (low quality).
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: jpeg-required-209-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <image x="10" y="10" width="300" height="300" xlink:href="../images/cloud411q25s.jpg"/>
+ <text x="320" y="100">optimised 4:1:1</text>
+ <text x="320" y="130">sequential</text>
+ <text x="320" y="160">high compression</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-01-t.svg
new file mode 100644
index 0000000000..8d4e677414
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-01-t.svg
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="CL" desc="Test that viewer has the basic capability to process the color property" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: paint-color-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ The purpose of this test is to determine if an application has the basic capability to process the 'color' property.
+ There are three subtests.
+ </p>
+ <p>
+ The first subtest, to the top left, is passed if the circle has a red fill. The second subtest, to the top right, is
+ passed if the circle has a red stroke. The third subtest shows a rectangle with a gradient fill, which has three stops.
+ The subtest is passed if central stop is red, fading off to blue to the left and pale yellow to the right.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-color-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+
+ <linearGradient xml:id="grad" color="red">
+ <stop offset="0.05" stop-color="#60F" />
+ <stop offset="0.5" stop-color="currentColor" />
+ <stop offset="0.95" stop-color="#FF6" />
+ </linearGradient>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g color="red">
+ <g color="inherit" fill="none" stroke="none">
+ <!-- inherit to check the property value, not the string, is being used -->
+ <circle cx="130" cy="80" r="60" fill="currentColor" />
+ <circle cx="350" cy="80" r="60" stroke="currentColor" stroke-width="4" />
+ </g>
+ </g>
+ <g color="blue">
+ <g color="inherit" fill="none" stroke="none">
+ <!-- blue color used to check color being scoped and inherited correctly -->
+ <rect x="60" y="215" width="360" height="80" fill="url(#grad)" />
+ </g>
+ </g>
+ <g font-size="30" fill="black">
+ <text x="120" y="170">fill</text>
+ <text x="310" y="170">stroke</text>
+ <text x="180" y="205">stop-color</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-03-t.svg
new file mode 100644
index 0000000000..dc65db62a6
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-03-t.svg
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="CL" desc="Test that viewer has the basic capability to render colors, specified as CSS attributes, using any of the equivalent forms." status="accepted"
+ approved="yes"
+ version="$Revision: 1.9 $" testname="$RCSfile: paint-color-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Purpose of test is to determine if the color datatype is supported. There are multiple syntaxes for specifying the
+ same color, such as #37F and #3377FF. For each of the six groups shown here, each of the shapes in the group uses
+ one of the syntactical forms and all in the group should be identical in color.
+ </p>
+ <p>
+ The first row uses five forms - 3-digit hex, 6-digit hex, rbg() integer form, rgb() percentage form, and named
+ ('HTML') colors.
+ </p>
+ <p>
+ The second row uses only four forms - 3-digit hex, 6-digit hex, rbg() integer form, rgb() percentage form - as
+ there are no HTML or X11 names for those colors.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-color-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- groups of five colors -->
+ <g>
+ <circle cx="75" cy="40" r="20" fill="#f00" />
+ <circle cx="115" cy="40" r="20" fill="#ff0000" />
+ <circle cx="75" cy="80" r="20" fill="rgb(255,0,0)" />
+ <circle cx="115" cy="80" r="20" fill="rgb(100%,0%,0%)" />
+ <polygon points="95,40 115,60 95,80 75,60" fill="red" />
+ </g>
+ <g>
+ <circle cx="200" cy="40" r="20" fill="#0f0" />
+ <circle cx="240" cy="40" r="20" fill="#00ff00" />
+ <circle cx="200" cy="80" r="20" fill="rgb(0,255,0)" />
+ <circle cx="240" cy="80" r="20" fill="rgb(0%,100%,0%)" />
+ <!-- 'lime' (full intensity green) NOT 'green' (half intensity green) -->
+ <polygon points="220,40 240,60 220,80 200,60" fill="lime" />
+ </g>
+ <g>
+ <circle cx="325" cy="40" r="20" fill="#00f" />
+ <circle cx="365" cy="40" r="20" fill="#0000ff" />
+ <circle cx="325" cy="80" r="20" fill="rgb(0,0,255)" />
+ <circle cx="365" cy="80" r="20" fill="rgb(0%,0%,100%)" />
+ <polygon points="345,40 365,60 345,80 325,60" fill="blue" />
+ </g>
+ <!-- no names for three digit colors except for 00 and ff -->
+ <!-- 11=17 22=34 33=51 44=68 55=85 66=102 77=119 88=136 99=153 aa=170 bb=187 cc=204 dd=221 ee=238 -->
+ <g>
+ <circle cx="75" cy="135" r="20" fill="#a01" />
+ <circle cx="115" cy="135" r="20" fill="#aa0011" />
+ <circle cx="75" cy="175" r="20" fill="rgb(170,0,17)" />
+ <circle cx="115" cy="175" r="20" fill="rgb(66.667%,0%,6.667%)" />
+ </g>
+ <g>
+ <circle cx="200" cy="135" r="20" fill="#3b3" />
+ <circle cx="240" cy="135" r="20" fill="#33bb33" />
+ <circle cx="200" cy="175" r="20" fill="rgb(51,187,51)" />
+ <circle cx="240" cy="175" r="20" fill="rgb(20%,73.333%,20%)" />
+ </g>
+ <g>
+ <circle cx="325" cy="135" r="20" fill="#57e" />
+ <circle cx="365" cy="135" r="20" fill="#5577ee" />
+ <circle cx="325" cy="175" r="20" fill="rgb(85,119,238)" />
+ <circle cx="365" cy="175" r="20" fill="rgb(33.333%,46.666%,93.333%)" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-04-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-04-t.svg
new file mode 100644
index 0000000000..8d9c4acb74
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-04-t.svg
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="CL" desc="Tests system colors" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: paint-color-04-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Tests system colors. The colors on your screen might not match the reference image at all, but they should at
+ minimum be legible and should preferably resemble the colors used on menus and other user interface elements on
+ your computer, pda or phone.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-color-04-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g xml:id="Scene_1" transform="translate(240, 180)">
+ <rect x="-230" y="-170" width="460" height="300" fill="Background" />
+ <rect x="-220" y="-160" width="440" height="280" fill="AppWorkspace" />
+ <rect x="-152" y="-108" width="317" height="221" fill="Window" />
+ <rect x="-152" y="-108" width="317" height="221" fill="none" stroke-width="3" stroke="WindowFrame" />
+ <g xml:id="contents" font-size="12" fill="WindowText">
+ <text x="-148" y="0">Lorem ipsum dolor sit amet, consectetuer adipiscing elit. </text>
+ <text x="-148" y="20">Vestibulum pulvinar. Duis laoreet, nunc vitae facilisis </text>
+ <text x="-148" y="40">tristique, pede sem iaculis mi, non consectetuer lorem </text>
+ <text x="-148" y="60">libero et est. Donec imperdiet purus sed odio. Duis </text>
+ <text x="-148" y="80">venenatis tortor eu lectus. Suspendisse sed metus at </text>
+ <text x="-148" y="100">metus viverra ultricies. Mauris porttitor, justo a vulputate</text>
+ </g>
+ <g xml:id="dropdown" transform="translate(2,0)">
+ <rect x="-150" y="-107" width="118" height="190" fill="ThreeDFace" xml:id="drop-bg" />
+ <rect x="-143" y="0" width="102" height="34" fill="Menu" />
+ <text x="-138" y="24" font-size="20" font-weight="bold" fill="MenuText">Load</text>
+ <rect x="-143" y="40" width="102" height="34" fill="Menu" />
+ <text x="-138" y="64" font-size="20" font-weight="bold" fill="MenuText">Save</text>
+ <path d="M-149 83 h114 v-94" stroke-width="4" stroke="ThreeDDarkShadow" fill="none" />
+ <path d="M-149 83 v-94 h114" stroke-width="4" stroke="ThreeDLightShadow" fill="none" />
+ </g>
+ <g xml:id="menubar">
+ <rect x="-148" y="-62" width="310" height="46" fill="ThreeDLightShadow" />
+ <path d="M152 -52 l 10 -10 v 46 h -311 l10-10 z" fill="ThreeDDarkShadow" />
+ <rect x="-144" y="-58" width="302" height="37" fill="ThreeDFace" />
+ <text x="-141" y="-32" font-size="20" font-weight="bold" fill="HighlightText">File</text>
+ <text x="-90" y="-32" font-size="20" font-weight="bold" fill="MenuText">Edit</text>
+ </g>
+ <g xml:id="windowdecoration">
+ <rect x="-149" y="-106" width="311" height="42" fill="ActiveCaption" stroke-width="4" stroke="ActiveBorder" xml:id="windowbar" />
+ <text x="5" y="-78" text-anchor="middle" font-size="24" font-weight="bold" fill="CaptionText">Lorem</text>
+ <g xml:id="button">
+ <rect x="120" y="-99" rx="8" width="26" height="26" fill="ButtonFace" />
+ <rect x="120" y="-99" rx="8" width="24" height="24" fill="ButtonHighlight" />
+ <rect x="122" y="-97" rx="8" width="24" height="24" fill="ButtonShadow" />
+ <rect x="122" y="-97" rx="8" width="22" height="22" fill="ButtonFace" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-05-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-05-t.svg
new file mode 100644
index 0000000000..bb8e5436dc
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-05-t.svg
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="CN" desc="This tests the correct behavior or currentcolor when specified in multiple places." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: paint-color-05-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Tests the color that is used for the currentColor value in the fill attribute when more than one color is specified.</p>
+ <p>This is illustrated using a single rectangle that is a child of a group element. A fill is specified for the group element but not the rectangle. Colour is specifed for the rectangle and the group element. The user agent should render the rectangle with a RED fill.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-color-05-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g fill="currentColor" color="red">
+ <rect x="120" y="60" width="150" height="150" color="blue" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-201-t.svg
new file mode 100644
index 0000000000..87e4596e73
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-color-201-t.svg
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN" owner="CL" desc="test the sixteen color names for Tiny" status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: paint-color-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Tests the sixteen color names that must be supported in SVG Tiny.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-color-201-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <!-- color names -->
+ <rect x="10" y="30" width="25" height="25" fill="black"/>
+ <rect x="10" y="60" width="25" height="25" fill="silver"/>
+ <rect x="10" y="90" width="25" height="25" fill="gray"/>
+ <rect x="10" y="120" width="25" height="25" fill="white"/>
+ <rect x="10" y="150" width="25" height="25" fill="maroon"/>
+ <rect x="10" y="180" width="25" height="25" fill="red"/>
+ <rect x="10" y="210" width="25" height="25" fill="purple"/>
+ <rect x="10" y="240" width="25" height="25" fill="fuchsia"/>
+
+ <!-- rrgb values -->
+ <rect x="35" y="30" width="25" height="25" fill="rgb( 0, 0, 0)"/>
+ <rect x="35" y="60" width="25" height="25" fill="rgb(192, 192, 192)"/>
+ <rect x="35" y="90" width="25" height="25" fill="rgb(128, 128, 128)"/>
+ <rect x="35" y="120" width="25" height="25" fill="rgb(255, 255, 255)"/>
+ <rect x="35" y="150" width="25" height="25" fill="rgb(128, 0, 0)"/>
+ <rect x="35" y="180" width="25" height="25" fill="rgb(255, 0, 0)"/>
+ <rect x="35" y="210" width="25" height="25" fill="rgb(128, 0, 128)"/>
+ <rect x="35" y="240" width="25" height="25" fill="rgb(255, 0, 255)"/>
+
+ <!-- make white visible -->
+ <rect x="10" y="120" width="50" height="25" fill="none" stroke="black"/>
+
+ <!-- labels -->
+ <text x="70" y="50">black</text>
+ <text x="70" y="80">silver</text>
+ <text x="70" y="110">gray</text>
+ <text x="70" y="140">white</text>
+ <text x="70" y="170">maroon</text>
+ <text x="70" y="200">red</text>
+ <text x="70" y="230">purple</text>
+ <text x="70" y="260">fuchsia</text>
+
+ <!-- rgb values -->
+ <rect x="275" y="30" width="25" height="25" fill="green"/>
+ <rect x="275" y="60" width="25" height="25" fill="lime"/>
+ <rect x="275" y="90" width="25" height="25" fill="olive"/>
+ <rect x="275" y="120" width="25" height="25" fill="yellow"/>
+ <rect x="275" y="150" width="25" height="25" fill="navy"/>
+ <rect x="275" y="180" width="25" height="25" fill="blue"/>
+ <rect x="275" y="210" width="25" height="25" fill="teal"/>
+ <rect x="275" y="240" width="25" height="25" fill="aqua"/>
+
+ <!-- color names -->
+ <rect x="250" y="30" width="25" height="25" fill="rgb( 0, 128, 0)"/>
+ <rect x="250" y="60" width="25" height="25" fill="rgb( 0, 255, 0)"/>
+ <rect x="250" y="90" width="25" height="25" fill="rgb(128, 128, 0)"/>
+ <rect x="250" y="120" width="25" height="25" fill="rgb(255, 255, 0)"/>
+ <rect x="250" y="150" width="25" height="25" fill="rgb( 0, 0, 128)"/>
+ <rect x="250" y="180" width="25" height="25" fill="rgb( 0, 0, 255)"/>
+ <rect x="250" y="210" width="25" height="25" fill="rgb( 0, 128, 128)"/>
+ <rect x="250" y="240" width="25" height="25" fill="rgb( 0, 255, 255)"/>
+
+ <!-- labels -->
+ <text x="310" y="50">green</text>
+ <text x="310" y="80">lime</text>
+ <text x="310" y="110">olive</text>
+ <text x="310" y="140">yellow</text>
+ <text x="310" y="170">navy</text>
+ <text x="310" y="200">blue</text>
+ <text x="310" y="230">teal</text>
+ <text x="310" y="260">aqua</text>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-01-t.svg
new file mode 100644
index 0000000000..40884c4a08
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-01-t.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="KMC" desc="Test that viewer has the basic capability to handle colour and 'none' values on the 'fill' property." status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: paint-fill-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verify the basic capability to handle the fill properties fill:none, and fill with a color (fill:red)</p>
+ <p>There should be two rectangles, the rectangle on the left hollow (fill:none) and the rectangle on the right filled with red.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-fill-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="36" x="40" y="42">Basic paint: fill properties.</text>
+ <!-- ============================================================================= -->
+ <!-- Draw two simple rectangles. One without fill other with fill:red -->
+ <!-- ============================================================================= -->
+ <rect xml:id="fill-01" fill="none" stroke="#000000" x="75" y="70" width="100" height="160" />
+ <rect xml:id="fill-02" fill="red" stroke="#000000" x="275" y="70" width="100" height="160" />
+ <text font-size="36" x="75" y="280">fill="none"</text>
+ <text font-size="36" x="275" y="280">fill="red"</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-02-t.svg
new file mode 100644
index 0000000000..2299dc5af0
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-02-t.svg
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="KMC" desc="Test that viewer has the basic capability to handle the 'currentColor' value on the 'fill' property." status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: paint-fill-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The test uses the "currentColor" value for the "fill" attribute.</p>
+ <p>
+ The rectangle on the left should be green filled, the rectangle on the right should be blue. The text above the
+ rectangles should be black.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-fill-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g color="green">
+ <text font-size="36" x="30" y="42">Basic paint: fill properties.</text>
+ <text font-size="36" x="100" y="80">fill="currentColor"</text>
+ <!-- ====================================================================== -->
+ <!-- Second set of rectangles with fill:currentColor -->
+ <!-- ====================================================================== -->
+ <rect xml:id="fill-03" fill="currentColor" stroke="#000000" x="75" y="110" width="100" height="140" />
+ <rect xml:id="fill-04" color="blue" fill="currentColor" stroke="#000000" x="275" y="110" width="100" height="140" />
+ <text font-size="36" x="80" y="280">green</text>
+ <text font-size="36" x="290" y="280">blue</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-03-t.svg
new file mode 100644
index 0000000000..dfa0379ccd
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-03-t.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="KMC" desc="Test that viewer has the basic capability to handle the 'fill-rule' property." status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: paint-fill-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verify the basic capability to handle the fill rule properties evenodd and nonzero</p>
+ <p>There should be two red filled stars, the leftmost star should be unfilled in the very center.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-fill-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="36" x="30" y="42">Basic paint: fill properties.</text>
+ <!-- ====================================================================== -->
+ <!-- Third test fill-rule:xeenodd and fill-rule:nonzero -->
+ <!-- ====================================================================== -->
+ <path fill="red" fill-rule="evenodd" d="M 110 75 l 50 160 l -130 -100 l 160 0 l -130 100 z" />
+ <path fill="red" fill-rule="nonzero" d="M 365 75 l 50 160 l -130 -100 l 160 0 l -130 100 z" />
+ <text font-size="26" x="10" y="282">fill-rule="evenodd"</text>
+ <text font-size="26" x="260" y="282">fill-rule="nonzero"</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-04-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-04-t.svg
new file mode 100644
index 0000000000..ffa73e2406
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-04-t.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="TT" desc="Test inheritance of painting properties." status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: paint-fill-04-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This tests inheritance of three properties: "fill", "stroke" and "stroke-width". There is a "g" element (id="G1")
+ which sets fill="blue", stroke="red", and stroke-width="5". The first two rectangles on top should inherit all
+ those properties. The middle left rectangle has fill="yellow" and stroke-width="2", it should inherit the
+ stroke="red" from the parent container. The middle rectangle on the right has stroke="yellow", it should inherit
+ fill and stroke-width from the parent "g". The bottom two rectangles are in another "g" element (id="G2") which
+ is a child of "G1". "G2" sets fill="yellow". It should inherit the stroke and stroke width from the parent "G1".
+ The two bottom rectangles set no fill or stroke properties, they should inherit through the parents, stroke="red"
+ and stroke-width="5".
+ </p>
+ <p>The rendered picture should match the reference image, except for possible variations in the labeling text (per CSS2 rules).</p>
+ <p>
+ The test uses the "rect" element, as well as basic fill (solid primary colors), stroke (black 1-pixel lines),
+ font-family (Arial) and font-size properties.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-fill-04-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g xml:id="G1" fill="blue" stroke="red" stroke-width="5" transform="translate(120,30)">
+ <rect x="0" y="0" width="90" height="70" />
+ <rect x="100" y="0" width="90" height="70" />
+ <rect x="0" y="80" width="90" height="70" fill="yellow" stroke-width="2" />
+ <rect x="100" y="80" width="90" height="70" stroke="yellow" />
+ <g xml:id="G2" fill="yellow">
+ <rect x="0" y="160" width="90" height="70" />
+ <rect x="100" y="160" width="90" height="70" />
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-05-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-05-t.svg
new file mode 100644
index 0000000000..5439773bec
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-fill-05-t.svg
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="DJ" owner="CN" desc="Test using fill-opacity values for rect element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: paint-fill-05-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test using "fill-opacity" values for "rect" element. This test verifies that opacity is clamped to the specified range.</p>
+ <p>
+ The six rect elements on the left have varying 'fill-opacity' values within the valid range of 0 to 1. The six elements
+ on the right have 'fill-opacity' values outside the 0 to 1 range, and must be clamped. The top three rect elements on
+ the right must have their 'fill-opacity' clamped to 0, while the bottom three rect elements on the right must be clamped
+ to 1.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-fill-05-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- Use multiple values for opacity -->
+ <rect x="20" y="20" width="60" height="60" fill-opacity="0.0" fill="#0000FF" stroke="black" />
+ <rect x="50" y="50" width="60" height="60" fill-opacity="0.2" fill="#0000FF" stroke="black" />
+ <rect x="80" y="80" width="60" height="60" fill-opacity="0.4" fill="#0000FF" stroke="black" />
+ <rect x="110" y="110" width="60" height="60" fill-opacity="0.6" fill="#0000FF" stroke="black" />
+ <rect x="140" y="140" width="60" height="60" fill-opacity="0.8" fill="#0000FF" stroke="black" />
+ <rect x="170" y="170" width="60" height="60" fill-opacity="1.0" fill="#0000FF" stroke="black" />
+ <!-- Values outside the range 0.0 - 1.0 should be clamped to this range -->
+ <rect x="200" y="20" width="60" height="60" fill-opacity="-100.0" fill="#0000FF" stroke="black" />
+ <rect x="230" y="50" width="60" height="60" fill-opacity="-10.0" fill="#0000FF" stroke="black" />
+ <rect x="260" y="80" width="60" height="60" fill-opacity="-0.1" fill="#0000FF" stroke="black" />
+ <rect x="290" y="110" width="60" height="60" fill-opacity="1.1" fill="#0000FF" stroke="black" />
+ <rect x="320" y="140" width="60" height="60" fill-opacity="10.0" fill="#0000FF" stroke="black" />
+ <rect x="350" y="170" width="60" height="60" fill-opacity="100.0" fill="#0000FF" stroke="black" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-04-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-04-t.svg
new file mode 100644
index 0000000000..c8584fc0cb
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-04-t.svg
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="HS" desc="Test that checks the capability of the stop element in linear and radial gradients." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: paint-grad-04-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test that checks the capability of the stop element in linear and radial gradients.</p>
+ <p>
+ The first rectangle has a linear gradient fill with a vector starting at top left and going to bottom right. The
+ stop colors are at 20% spacing apart and are in the following order : violet, blue, lime, yellow, orange, red.
+ Because the gradient vector vector goes from (0,0) to (1,1) in object bounding box space and because the object
+ bounding box has a larger width than height, the gradient vector is skewed off of a pure 45 degree angle. The
+ gradient stripes are also skewed so that they are no longer perpendicular to the gradient vector.
+ </p>
+ <p>
+ The next rectangle has a radial gradient fill with a multi-color stops from innermost to outermost in the following
+ order : black, yellow, red, blue, white, green.
+ </p>
+ <p>
+ The rendered picture should match the reference image exactly, except for possible variations in the labelling
+ text (per CSS2 rules).
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-04-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- ====================================================================== -->
+ <!-- Very simple black to red radial gradient ======== -->
+ <!-- ====================================================================== -->
+ <linearGradient xml:id="Grad1" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="1">
+ <stop stop-color="rgb(238,130,238)" offset="0" />
+ <stop stop-color="blue" offset="0.2" />
+ <stop stop-color="lime" offset="0.4" />
+ <stop stop-color="yellow" offset="0.6" />
+ <stop stop-color="rgb(255,165,0)" offset="0.8" />
+ <stop stop-color="red" offset="1" />
+ </linearGradient>
+ <rect x="20" y="20" width="440" height="80" fill="url(#Grad1)" />
+ <text font-size="30" x="20" y="130">Multi-color linear gradient.</text>
+ <!-- ====================================================================== -->
+ <!-- Radial gradient on the stroke of a rectangle ======== -->
+ <!-- ====================================================================== -->
+ <radialGradient xml:id="Grad2" gradientUnits="userSpaceOnUse" cx="240" cy="210" r="220" fx="240" fy="210">
+ <stop stop-color="black" offset="0" />
+ <stop stop-color="yellow" offset="0.2" />
+ <stop stop-color="red" offset="0.4" />
+ <stop stop-color="blue" offset="0.6" />
+ <stop stop-color="white" offset="0.8" />
+ <stop stop-color="green" offset="1" />
+ </radialGradient>
+ <rect x="20" y="150" width="440" height="80" fill="url(#Grad2)" stroke-width="40" />
+ <text font-size="30" x="20" y="260">Multi-color radial gradient.</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-05-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-05-t.svg
new file mode 100644
index 0000000000..65bcb9f4fa
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-05-t.svg
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="HS" desc="Test that checks the capability of the stop opacity in linear and radial gradients." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: paint-grad-05-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test that checks the capability of the stop opacity in linear and radial gradients.</p>
+ <p>
+ There are two tests which contain rectangles with gradients using stop-opacity properties. A cyan color text string
+ "Background" is put behind both of the rectangles to help demonstrate the opacity concept. From top-down the appearance
+ of objects is as follows.
+ </p>
+ <p>
+ The first rectangle has a linear gradient fill with a vector starting at top left and going to bottom right. The stop
+ colors are at 20% spacing apart and are in the following order : violet, blue, lime, yellow, orange, red. Also a stop
+ opacity is given to the colors in the following order: 1, 0.2, 0.5, 0, 0.8, 1 Because the gradient vector vector goes
+ from (0,0) to (1,1) in object bounding box space and because the object bounding box has a larger width than height,
+ the gradient vector is skewed off of a pure 45 degree angle. The gradient stripes are also skewed so that they are no
+ longer perpendicular to the gradient vector.
+ </p>
+ <p>
+ The next rectangle has a radial gradient fill with a multi-color stops from innermost to outermost in the following
+ order : black, yellow, red, blue, white, green. Also a stop opacity is given to the colors in the following order: 1,
+ 0.2, 0.5, 0, 0.8, 1
+ </p>
+ <p>
+ The rendered picture should match the reference image exactly, except for possible variations in the labelling text
+ (per CSS2 rules).
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-05-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- ====================================================================== -->
+ <!-- Very simple black to red radial gradient ======== -->
+ <!-- ====================================================================== -->
+ <text font-size="60" fill="aqua" x="70" y="80">Background</text>
+ <linearGradient xml:id="Grad1" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="1">
+ <stop stop-color="rgb(238,130,238)" stop-opacity="1" offset="0" />
+ <stop stop-color="blue" stop-opacity="0" offset="0.2" />
+ <stop stop-color="lime" stop-opacity="0.5" offset="0.4" />
+ <stop stop-color="yellow" stop-opacity="0.2" offset="0.6" />
+ <stop stop-color="rgb(255,165,0)" stop-opacity="0.8" offset="0.8" />
+ <stop stop-color="red" stop-opacity="1" offset="1" />
+ </linearGradient>
+ <rect x="20" y="20" width="440" height="80" fill="url(#Grad1)" />
+ <!-- ====================================================================== -->
+ <!-- Radial gradient on the stroke of a rectangle ======== -->
+ <!-- ====================================================================== -->
+ <text font-size="60" fill="aqua" x="70" y="210">Background</text>
+ <radialGradient xml:id="Grad2" gradientUnits="userSpaceOnUse" cx="240" cy="210" r="220" fx="240" fy="210">
+ <stop stop-color="black" stop-opacity="1" offset="0" />
+ <stop stop-color="yellow" stop-opacity="0" offset="0.2" />
+ <stop stop-color="red" stop-opacity="0.5" offset="0.4" />
+ <stop stop-color="blue" stop-opacity="0.2" offset="0.6" />
+ <stop stop-color="white" stop-opacity="0.8" offset="0.8" />
+ <stop stop-color="green" stop-opacity="1" offset="1" />
+ </radialGradient>
+ <rect x="20" y="150" width="440" height="80" fill="url(#Grad2)" stroke-width="40" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-07-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-07-t.svg
new file mode 100644
index 0000000000..c0bdcf6cd9
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-07-t.svg
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="HS" desc="Test that the viewer has basic capability to handle linear gradients on fills and stroke of objects . This means it needs to understand the following elements : &lt;linearGradient&gt;, &lt;stop&gt; and the following properties : stop-color, fill:url(# ), stroke(url# )" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: paint-grad-07-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test that the viewer has basic capability to handle linear gradients on fills and stroke of objects and text.</p>
+ <p>
+ This test uses the following elements : &lt;linearGradient&gt;, &lt;stop&gt; and the following properties : stop-color,
+ fill:url(# ), stroke(url# )
+ </p>
+ <p>
+ Both elements in this test use the same simple gradient. It is a linear gradient from blue (left) to red (right). From
+ top-down the appearance of objects is as follows.
+ </p>
+ <p>The top rectangle should be filled with the gradient.</p>
+ <p>The next rectangle has no fill, but has a thick stroke on which the gradient is applied.</p>
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-07-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="scale(1, 1.5)">
+ <!-- ====================================================================== -->
+ <!-- Very simple blue to red linear gradient from left to right ========== -->
+ <!-- ====================================================================== -->
+ <linearGradient xml:id="Gradient" gradientUnits="userSpaceOnUse" x1="10" y1="10" x2="440" y2="10">
+ <stop stop-color="blue" offset="0" />
+ <stop stop-color="red" offset="1" />
+ </linearGradient>
+ <!-- ====================================================================== -->
+ <!-- Linear gradient on the fill of a rectangle ======== -->
+ <!-- ====================================================================== -->
+ <rect x="10" y="10" width="430" height="60" fill="url(#Gradient)" />
+ <text font-size="24" x="10" y="90">Linear gradient filled rectangle</text>
+ <!-- ====================================================================== -->
+ <!-- Linear gradient on the stroke of a rectangle ======== -->
+ <!-- ====================================================================== -->
+ <rect x="25" y="110" width="400" height="30" fill="none" stroke="url(#Gradient)" stroke-width="20" />
+ <text font-size="24" x="10" y="170">Linear gradient on stroke of rectangle</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-08-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-08-t.svg
new file mode 100644
index 0000000000..06b3877222
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-08-t.svg
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="HS" desc="Test that the viewer has basic capability to handle linear gradients on fills and stroke of objects and text. This means it needs to understand the following elements : &lt;linearGradient&gt;, &lt;stop&gt; and the following properties : stop-color, fill:url(# ), stroke(url# )" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: paint-grad-08-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test that the viewer has basic capability to handle linear gradients on fills and stroke of text.</p>
+ <p>
+ This test uses the following elements : &lt;linearGradient&gt;, &lt;stop&gt; and the following properties : stop-color,
+ fill:url(# ), stroke(url# )
+ </p>
+ <p>
+ Both elements in this test use the same simple gradient. It is a linear gradient from blue (left) to red (right). From
+ top-down the appearance of objects is as follows.
+ </p>
+ <p>The first item is a text string "Gradient on fill" with the gradient on the fill of the text.</p>
+ <p>The second item is a text string that is not filled. It has a 2 user unit stroke on which the gradient is applied.</p>
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-08-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font xml:id="MyFont" horiz-adv-x="416">
+ <font-face font-family="MyFont" units-per-em="1000" panose-1="2 0 0 6 3 0 0 2 0 4" ascent="700" descent="-127" alphabetic="0" />
+ <missing-glyph horiz-adv-x="233" />
+ <glyph unicode=" " glyph-name="space" horiz-adv-x="233" />
+ <glyph unicode="G" glyph-name="G" horiz-adv-x="547" d="M40 700V0H510V383H295V253H360V150H190V550H510V700H40Z" />
+ <glyph unicode="a" glyph-name="a" horiz-adv-x="435" d="M71 550L3 0H143L154 119H282L293 0H433L365 550H71ZM168 259L182 410H254L268 259H168Z" />
+ <glyph unicode="d" glyph-name="d" horiz-adv-x="519" d="M27 550V410H87V140H27V0H482V550H27ZM230 410H339V140H230V410Z" />
+ <glyph unicode="e" glyph-name="e" horiz-adv-x="442" d="M37 550V410V0H419V130H180V210H299V340H180V420H419V550H37Z" />
+ <glyph unicode="f" glyph-name="f" horiz-adv-x="428" d="M37 550V410V0H180V196H349V326H180V420H410V550H37Z" />
+ <glyph unicode="i" glyph-name="i" horiz-adv-x="217" d="M37 550V410V0H180V550H37Z" />
+ <glyph unicode="k" glyph-name="k" horiz-adv-x="472" d="M180 207H233L325 0H480L344 284L474 550H319L233 347H180V550H37V410V0H180V207Z" />
+ <glyph unicode="l" glyph-name="l" horiz-adv-x="435" d="M37 0H425V130H180V550H37V410V0Z" />
+ <glyph unicode="n" glyph-name="n" horiz-adv-x="518" d="M180 550H37V410V0H180V324L338 0H481V550H338V226L180 550Z" />
+ <glyph unicode="o" glyph-name="o" horiz-adv-x="484" d="M37 550V0H447V550H37ZM180 410H304V140H180V410Z" />
+ <glyph unicode="r" glyph-name="r" horiz-adv-x="485" d="M37 550V410V0H180V164H222L305 0H465L367 174H444V550H37ZM180 420H301V294H180V420Z" />
+ <glyph unicode="s" glyph-name="s" horiz-adv-x="468" d="M34 550V410V218H291V120H34V0H434V338H177V430H434V550H34Z" />
+ <glyph unicode="t" glyph-name="t" horiz-adv-x="417" d="M5 550V410H137V0H280V410H412V550H5Z" />
+ </font>
+ </defs>
+ <!-- ====================================================================== -->
+ <!-- Very simple blue to red linear gradient from left to right ========== -->
+ <!-- ====================================================================== -->
+ <linearGradient xml:id="Gradient" gradientUnits="userSpaceOnUse" x1="10" y1="10" x2="440" y2="10">
+ <stop stop-color="blue" offset="0" />
+ <stop stop-color="red" offset="1" />
+ </linearGradient>
+ <!-- ====================================================================== -->
+ <!-- Gradient on fill of text ======== -->
+ <!-- ====================================================================== -->
+ <text font-family="MyFont" font-size="68" fill="url(#Gradient)" x="20" y="90">Gradient on fill</text>
+ <text font-size="30" x="40" y="130">Linear gradient on filled text</text>
+ <!-- ====================================================================== -->
+ <!-- Gradient on stroke of text ======== -->
+ <!-- ====================================================================== -->
+ <text font-family="MyFont" x="20" y="220" font-size="55" fill="none" stroke="url(#Gradient)" stroke-width="3">Gradient on stroke</text>
+ <text font-size="30" x="30" y="260">Linear gradient on stroke of text</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-09-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-09-t.svg
new file mode 100644
index 0000000000..4d4ceac465
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-09-t.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="HS" desc="Test that the viewer can handle the gradientUnits attribute on linear gradients." status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: paint-grad-09-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test that the viewer can handle the gradientUnits attribute on linear gradients. It tests the following values of
+ gradientUnits : default (objectBoundingBox), specifying objectBoundingBox, and specifying userSpaceOnUse.
+ </p>
+ <p>From top-down the appearance of objects is as follows.</p>
+ <p>
+ The first rectangle uses the default attributes on the linearGradient element. Therefore the linear gradient should
+ default to objectBoundingBox. It should appear from the left edge of the rectangle (blue) to the right edge of the
+ rectangle (red). The rectangle is smaller than the viewport, because a previous version of the SVG spec had the
+ default value be 'viewport'. The test fails if only a portion of the gradient is shown.
+ </p>
+ <p>The next rectangle uses gradientUnits=objectBoundingBox. The linear gradient should travel from blue (top) to red (bottom).</p>
+ <p>
+ The last rectangle uses gradientUnits=userSpaceOnUse. The rectangle element is given it's own transformation and the
+ gradient is assumed to be in this user space. The gradient should appear as a linear gradient from red (left) to blue
+ (right).
+ </p>
+ <p>
+ The rendered picture should match the reference image exactly, except for possible variations in the labelling text
+ (per CSS2 rules).
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-09-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="15" x="10" y="25">Testing gradientUnits attribute</text>
+ <!-- ====================================================================== -->
+ <!-- Linear gradient with default attributes on <linear gradient> element. -->
+ <!-- ====================================================================== -->
+ <linearGradient xml:id="Grad1">
+ <stop stop-color="red" offset="0" />
+ <stop stop-color="blue" offset="1" />
+ </linearGradient>
+ <rect x="125" y="35" width="200" height="50" fill="url(#Grad1)" />
+ <text font-size="12" x="10" y="100">Linear gradient with default attributes (thus, same as objectBoundingBox)</text>
+ <!--text font-family="Arial" font-size="12" x="10" y="125">Gradient is from the viewport left edge (red) to viewport right edge (blue)</text-->
+ <text font-size="12" x="10" y="115">Gradient is from the object left edge (red) to object right edge (blue)</text>
+ <!-- ====================================================================== -->
+ <!-- Linear gradient with gradientUnits=objectBoundingBox ======== -->
+ <!-- ====================================================================== -->
+ <linearGradient xml:id="Grad2" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="0" y2="1">
+ <stop stop-color="blue" offset="0" />
+ <stop stop-color="red" offset="1" />
+ </linearGradient>
+ <rect x="10" y="125" width="430" height="50" fill="url(#Grad2)" />
+ <text font-size="12" x="10" y="190">gradientUnits=objectBoundingBox</text>
+ <text font-size="12" x="10" y="205">Gradient is from the object top edge (blue) to object bottom edge (red)</text>
+ <!-- ====================================================================== -->
+ <!-- Gradient using gradientUnits="userSpaceOnUse" -->
+ <!-- ====================================================================== -->
+ <linearGradient xml:id="Grad3" x1="0" y1="0" x2="0" y2="430" gradientUnits="userSpaceOnUse">
+ <stop stop-color="red" offset="0" />
+ <stop stop-color="blue" offset="1" />
+ </linearGradient>
+ <rect transform="translate(10, 260) rotate(-90)" x="0" y="0" width="50" height="430" fill="url(#Grad3)" />
+ <text font-size="12" x="10" y="275">gradientUnits=userSpaceOnUse</text>
+ <text font-size="12" x="10" y="290">Gradient is from the object left edge (red) to object right edge (blue)</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-11-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-11-t.svg
new file mode 100644
index 0000000000..12dbc00196
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-11-t.svg
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="HS" desc="Test that the viewer has basic capability to handle radial gradients on fills and stroke of objects and text. This means it needs to understand the following elements : &lt;radialGradient&gt;, &lt;stop&gt; and the following properties : stop-color, fill:url(# ), stroke(url# )" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: paint-grad-11-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test that the viewer has basic capability to handle radial gradients on fills and stroke of objects and text.</p>
+ <p>
+ This test uses the following elements : &lt;radialGradient&gt;, &lt;stop&gt; and the following properties : stop-color,
+ fill:url(# ), stroke(url# )
+ </p>
+ <p>From top-down (left to right) the appearance of objects is as follows.</p>
+ <p>
+ The top left rectangle should be a radial gradient from black(in) to red(outside). The gradiant is applied to the
+ fill of the rectangle.
+ </p>
+ <p>
+ The next rectangle has no fill, but has a thick stroke on which the gradient is applied. The gradient goes from
+ red(in) to yellow (out).
+ </p>
+ <p>The next item is a text with a radial gradient on the fill. The gradient goes from black (in) to yellow (out).</p>
+ <p>The last item is a text with a 2 user unit stroke on which a black (in) to red (out) linear gradient is applied.</p>
+ <p>
+ The rendered picture should match the reference image exactly, except for possible variations in the labelling text
+ (per CSS2 rules).
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-11-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- ====================================================================== -->
+ <!-- Very simple black to red radial gradient ======== -->
+ <!-- ====================================================================== -->
+ <radialGradient gradientUnits="userSpaceOnUse" xml:id="Grad1" cx="75" cy="100" r="130">
+ <stop stop-color="black" offset="0" />
+ <stop stop-color="red" offset="1" />
+ </radialGradient>
+ <rect x="10" y="10" width="210" height="140" fill="url(#Grad1)" />
+ <text font-size="12" x="10" y="165">Radial gradient on fill of rectangle</text>
+ <!-- ====================================================================== -->
+ <!-- Radial gradient on the stroke of a rectangle ======== -->
+ <!-- ====================================================================== -->
+ <radialGradient xml:id="Grad2" gradientUnits="userSpaceOnUse" cx="295" cy="100" r="150">
+ <stop stop-color="red" offset="0" />
+ <stop stop-color="yellow" offset="1" />
+ </radialGradient>
+ <rect x="250" y="30" width="170" height="100" fill="none" stroke="url(#Grad2)" stroke-width="40" />
+ <text font-size="12" x="230" y="165">Radial gradient on stroke of rectangle</text>
+ <!-- ====================================================================== -->
+ <!-- Gradient on fill of text ======== -->
+ <!-- ====================================================================== -->
+ <radialGradient xml:id="Grad3" gradientUnits="userSpaceOnUse" cx="225" cy="180" r="90">
+ <stop stop-color="black" offset="0" />
+ <stop stop-color="yellow" offset="1" />
+ </radialGradient>
+ <text font-size="50" fill="url(#Grad3)" x="10" y="210">Gradient on text fill</text>
+ <text font-size="12" x="10" y="225">Radial gradient on text, black to yellow</text>
+ <!-- ====================================================================== -->
+ <!-- Gradient on stroke of text ======== -->
+ <!-- ====================================================================== -->
+ <radialGradient xml:id="Grad4" gradientUnits="userSpaceOnUse" cx="225" cy="245" r="90">
+ <stop stop-color="black" offset="0" />
+ <stop stop-color="red" offset="1" />
+ </radialGradient>
+ <text font-size="45" fill="none" stroke="url(#Grad4)" stroke-width="2" x="10" y="270">Gradient on text stroke</text>
+ <text font-size="12" x="10" y="285">Radial gradient on stroke of text, black to red</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-12-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-12-t.svg
new file mode 100644
index 0000000000..9d9bb0510f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-12-t.svg
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="HS" desc="Test that the viewer can handle the gradientUnits attribute on radial gradients." status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: paint-grad-12-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test that the viewer can handle the gradientUnits attribute on radial gradients. It tests the following values of
+ gradientUnits : default (objectBoundingBox), objectBoundingBox, and userSpaceOnUse.
+ </p>
+ <p>From top-down the appearance of objects is as follows.</p>
+ <p>
+ The first rectangle uses the default attributes on the radialGradient element. Therefore the radial gradient should
+ be relative to the object bounding box. It should appear from the center of the viewport (blue) to the edges of the
+ viewport (red). The rectangle is wider than tall so it the gradient should be elliptical, not circular.
+ </p>
+ <p>
+ The next rectangle uses gradientUnits=objectBoundingBox. The radial gradient should travel from a center of 20%, 20%
+ of the rectangle with a radius of 50%.
+ </p>
+ <p>
+ The last rectangle uses gradientUnits=userSpaceOnUse. The rectangle element is given it's own transformation and the
+ gradient is assumed to be in this user space. The gradient should appear in the center of the rectangle as a radial
+ gradient from red (center) to blue (edge).
+ </p>
+ <p>
+ The rendered picture should match the reference image exactly, except for possible variations in the labelling text
+ (per CSS2 rules).
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-12-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="15" x="10" y="25">Testing gradientUnits attribute</text>
+ <!-- ====================================================================== -->
+ <!-- Radial gradient with default attributes on <radial gradient> element. -->
+ <!-- ====================================================================== -->
+ <radialGradient xml:id="Grad1">
+ <stop stop-color="blue" offset="0" />
+ <stop stop-color="red" offset="1" />
+ </radialGradient>
+ <rect x="10" y="35" width="460" height="50" fill="url(#Grad1)" />
+ <text font-size="12" x="10" y="100">Radial gradient with default attributes (from blue to red)</text>
+ <text font-size="12" x="10" y="115">Gradient is blue at the object center and red at the object edges</text>
+ <!-- ====================================================================== -->
+ <!-- Radial gradient with gradientUnits=objectBoundingBox ======== -->
+ <!-- ====================================================================== -->
+ <radialGradient xml:id="Grad2" gradientUnits="objectBoundingBox" cx=".2" cy=".2" r=".5">
+ <stop stop-color="blue" offset="0" />
+ <stop stop-color="red" offset="1" />
+ </radialGradient>
+ <rect x="10" y="125" width="460" height="50" fill="url(#Grad2)" />
+ <text font-size="12" x="10" y="190">gradientUnits=objectBoundingBox</text>
+ <text font-size="12" x="10" y="205">cx=.2, cy=.2, r=.5</text>
+ <!-- ====================================================================== -->
+ <!-- Gradient using gradientUnits="userSpaceOnUse" -->
+ <!-- ====================================================================== -->
+ <radialGradient xml:id="Grad3" cx="25" cy="215" r="25" gradientUnits="userSpaceOnUse">
+ <stop stop-color="red" offset="0" />
+ <stop stop-color="blue" offset="1" />
+ </radialGradient>
+ <rect transform="translate(10, 260) rotate(-90)" x="0" y="0" width="50" height="460" fill="url(#Grad3)" />
+ <text font-size="12" x="10" y="275">gradientUnits=userSpaceOnUse</text>
+ <text font-size="12" x="10" y="290">Gradient is red to blue radial gradiant from center to horizontal bounds</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-15-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-15-t.svg
new file mode 100644
index 0000000000..bf4175918b
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-15-t.svg
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="CN" desc="Test linear and radial gradient defaults." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: paint-grad-15-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test linear and radial gradient defaults. Includes testing defaults for linear grad x1,y1,y2 = 0.0, x2 = 1.0 and
+ testing defaults for radial grad cx,cy,r = 0.5
+ </p>
+ <p>
+ The top rectangle must be blue at the lefthand side and red at the right hand side, fading smoothly accross. The
+ lower rectangle must be red at the edges with a black centre to the radial gradient at the centre of the
+ rectangle, and the gradient occupying the whole rectangle.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-15-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- Test defaults for linear grad x1,y1,y2 = 0, x2 = 1 -->
+ <linearGradient xml:id="defs1" gradientUnits="objectBoundingBox">
+ <stop stop-color="blue" offset="0" />
+ <stop stop-color="red" offset="1" />
+ </linearGradient>
+ <!-- Test defaults for radial grad cx,cy,r = 0.5 -->
+ <radialGradient xml:id="defs2" gradientUnits="objectBoundingBox">
+ <stop stop-color="black" offset="0" />
+ <stop stop-color="red" offset="1" />
+ </radialGradient>
+ <rect x="20" y="20" width="440" height="80" fill="url(#defs1)" />
+ <rect x="20" y="150" width="440" height="80" fill="url(#defs2)" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-16-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-16-t.svg
new file mode 100644
index 0000000000..1314bc8396
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-16-t.svg
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="CN" desc="Test gradient stop rules." status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: paint-grad-16-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test gradient stop rules. Including: No stops, like fill = none. One stop, like fill = black. If a stop less than
+ all previous stops, it is set equal to the largest stop. If two stops are equal the last stop controls the color
+ at the overlap point.
+ </p>
+ <p>
+ The top rectangle must have a red outline and no fill. The middle rectangle must have a solid black fill. The
+ lower rectangle must have a yellow to red to green linear gradient on the left-hand half and a solid blue fill
+ for the right hand half.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-16-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- No stops, like fill = none -->
+ <linearGradient xml:id="defs1" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="0"> </linearGradient>
+ <!-- One stop, like fill = black -->
+ <linearGradient xml:id="defs2" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="0">
+ <stop stop-color="black" offset="1" />
+ </linearGradient>
+ <!-- If a stop less than all previous stops, it is set equal to the largest stop-->
+ <!-- This also tests if two stops are equal the last stop controls the color at the overlap point-->
+ <linearGradient xml:id="defs3" gradientUnits="objectBoundingBox" x1="0" y1="0" x2="1" y2="0">
+ <stop stop-color="yellow" offset="0" />
+ <stop stop-color="red" offset=".25" />
+ <stop stop-color="green" offset=".5" />
+ <stop stop-color="blue" offset=".1" />
+ </linearGradient>
+ <rect x="20" y="10" width="440" height="80" fill="url(#defs1)" stroke="red" />
+ <rect x="20" y="110" width="440" height="80" fill="url(#defs2)" />
+ <rect x="20" y="210" width="440" height="80" fill="url(#defs3)" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-17-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-17-t.svg
new file mode 100644
index 0000000000..57f162f817
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-17-t.svg
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ED" desc="Test that checks that a gradient with objectBoundingBox is not applied on an element without width or height." status="accepted"
+ approved="yes"
+ version="$Revision: 1.9 $" testname="$RCSfile: paint-grad-17-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test has a gradient with gradientUnits='objectBoundingBox' which is a fade from black to white. The gradient
+ is used for the stroke of a line. Vertical and horizontal lines don't have a boundingbox, since they are
+ one-dimensional, even though the stroke-width makes it look like they should have a boundingbox with non-zero width
+ and height. See the coordinate chapter, last paragraph of 7.12.
+ </p>
+ <p>
+ The left rectangle has four 'line' elements rotated in different ways. The stroke for the lines have a green solid
+ stroke fallback which should be used if the gradient should be ignored. For this sub-test to pass there must be
+ three lines with solid green stroke, and one line (from bottom left to top right) with a gradient stroke, visible
+ in the rectangle.
+ </p>
+ <p>
+ The right rectangle is the same as the left rectangle except that the stroke paintservers don't have a fallback
+ specified. For this sub-test to pass only the line from bottom left to top right must be visible in the rectangle,
+ and it must have a gradient stroke.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-17-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <linearGradient xml:id="grad">
+ <stop offset="0" stop-color="black" />
+ <stop offset="1" stop-color="white" />
+ </linearGradient>
+ </defs>
+ <!-- sub-test 1: stroke with solid color fallback -->
+ <g transform="translate(50, 100) scale(0.3)">
+ <line x1="0" y1="180" x2="480" y2="180" stroke="url(#grad) #070" stroke-width="20" />
+ <line x1="0" y1="180" x2="480" y2="180" stroke="url(#grad) #070" stroke-width="20" transform="rotate(45 240 180)" />
+ <line x1="0" y1="180" x2="480" y2="180" stroke="url(#grad) #070" stroke-width="20" transform="rotate(90 240 180)" />
+ <line x1="410" y1="10" x2="70" y2="350" stroke="url(#grad) #070" stroke-width="20" />
+ <rect x="0" y="-60" width="480" height="480" fill="none" stroke="black" />
+ </g>
+ <text x="120" y="250" text-anchor="middle">With fallback</text>
+ <!-- sub-test 2: stroke without a fallback -->
+ <g transform="translate(280,100) scale(0.3)">
+ <line x1="0" y1="180" x2="480" y2="180" stroke="url(#grad)" stroke-width="20" />
+ <line x1="0" y1="180" x2="480" y2="180" stroke="url(#grad)" stroke-width="20" transform="rotate(45 240 180)" />
+ <line x1="0" y1="180" x2="480" y2="180" stroke="url(#grad)" stroke-width="20" transform="rotate(90 240 180)" />
+ <line x1="410" y1="10" x2="70" y2="350" stroke="url(#grad)" stroke-width="20" />
+ <rect x="0" y="-60" width="480" height="480" fill="none" stroke="black" />
+ </g>
+ <text x="350" y="250" text-anchor="middle">Without fallback</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-18-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-18-t.svg
new file mode 100644
index 0000000000..d0b376158f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-18-t.svg
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="CC" desc="Tests inherit and currentColor on gradient stops" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: paint-grad-18-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test shows rectangles filled with gradient. Several gradients are defined, with two stops:</p>
+ <p>For the top-left rectangle's gradient: The first stop defines a fully-opaque green color. The second stop explicitly inherits (i.e. using the 'inherit' keyword) its stop-color. The result should be that the top-left rectangle is filled with a gradient from green to red since the stop-color is inherited from the location of the gradient definition.</p>
+ <p>For the top-right rectangle's gradient: The first stop defines a fully-opaque green color. The second stop defines a green stop-color but explicitly inherits (i.e. using the 'inherit' keyword) the stop-opacity. The result should be that the top-right rectangle filled in green with a gradient opacity.</p>
+ <p>For the bottom-left rectangle's gradient: The first stop defines a fully-opaque green color. The second stop does not specify the stop-color and the stop-opacity. Since both properties are not inherited, the initial value should be used. The result should be that the lower-left rectangle filled with a gradient going from fully-opaque green to fully-opaque black.</p>
+ <p>For the bottom-right rectangle's gradient: The first stop defines a fully-opaque green color. The second stop specifies the stop-color using the 'currentColor' keyword. The result should be that the lower-right rectangle filled with a gradient going from fully-opaque green to fully-opaque yellow.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-18-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g xml:id="g0" stop-color="red" stop-opacity="0.5" color="yellow">
+ <linearGradient xml:id="MyGradient1" stop-color="inherit">
+ <stop offset="0" stop-color="green" stop-opacity="1" />
+ <stop offset="1" stop-color="inherit" stop-opacity="1" />
+ </linearGradient>
+ <linearGradient xml:id="MyGradient2" stop-opacity="inherit">
+ <stop offset="0" stop-color="green" stop-opacity="1" />
+ <stop offset="1" stop-color="green" stop-opacity="inherit" />
+ </linearGradient>
+ <linearGradient xml:id="MyGradient3">
+ <stop offset="0" stop-color="green" stop-opacity="1" />
+ <stop offset="1" />
+ </linearGradient>
+ <linearGradient xml:id="MyGradient4">
+ <stop offset="0" stop-color="green" stop-opacity="1" />
+ <stop offset="1" stop-color="currentColor" stop-opacity="1" />
+ </linearGradient>
+ </g>
+ <g xml:id="g1" stop-color="blue">
+ <rect xml:id="r1" fill="url(#MyGradient1)" width="100" height="100" x="50" y="50" />
+ </g>
+ <g xml:id="g2" stop-opacity="1">
+ <rect xml:id="r2" fill="url(#MyGradient2)" width="100" height="100" x="200" y="50" />
+ </g>
+ <g xml:id="g3" stop-opacity="1" stop-color="blue">
+ <rect xml:id="r3" fill="url(#MyGradient3)" width="100" height="100" x="50" y="200" />
+ </g>
+ <g xml:id="g4" color="blue">
+ <rect xml:id="r4" fill="url(#MyGradient4)" width="100" height="100" x="200" y="200" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-202-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-202-t.svg
new file mode 100644
index 0000000000..c226d01143
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-202-t.svg
@@ -0,0 +1,82 @@
+<?xml version="1.0" standalone="no"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="AE" desc="Stop Opacity Attribute with Text" status="accepted"
+ approved="yes"
+ testname="$RCSfile: paint-grad-202-t.svg,v $" version="$Revision: 1.7 $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Stop Opacity Attribute with Text</p>
+ <p>
+ There are three lines of text. For this test to pass each line of text must have the same gradient
+ from green to blue all set to a 'stop-opacity' of 0.4 . The reference rect at the bottom has a
+ similar gradient but with 'stop-opacity set to 1. The text of the poem should be lighter than
+ the reference line.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-202-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g fill="#555" text-anchor="middle">
+ <text fill="#000" x="240" y="30" xml:id="display-title">Stop Opacity Attribute with Text</text>
+ <g font-size="14">
+ <text x="240" y="50" xml:id="comment-1">All three lines of text must have the same transparent gradient - </text>
+ <text x="240" y="65" xml:id="comment-2">from green to blue, set at 0.4 'stop-opacity'. The reference rect at</text>
+ <text x="240" y="80" xml:id="comment-3">the bottom has a similar gradient but with 'stop-opacity set to 1.</text>
+ </g>
+ </g>
+ <defs>
+ <linearGradient xml:id="LinearGrad-transparent-z">
+ <stop stop-opacity="0.4" stop-color="green" offset="0.03"/>
+ <stop stop-opacity="0.4" stop-color="blue" offset="0.40"/>
+ <stop stop-opacity="0.4" stop-color="fuchsia" offset="0.66"/>
+ <stop stop-opacity="0.4" stop-color="purple" offset="0.98"/>
+ </linearGradient>
+ <linearGradient xml:id="LinearGrad-transparent">
+ <stop stop-opacity="0.4" stop-color="green" offset="0.43"/>
+ <stop stop-opacity="0.4" stop-color="blue" offset="0.98"/>
+ </linearGradient>
+ <linearGradient xml:id="LinearGrad-opaque">
+ <stop stop-opacity="1" stop-color="green" offset="0.43"/>
+ <stop stop-opacity="1" stop-color="blue" offset="0.98"/>
+ </linearGradient>
+ <g xml:id="poem">
+ <text x="0" y="0">old pond</text>
+ <text x="0" y="30">a frog leaps in -</text>
+ <text x="0" y="60">a moment after, silence</text>
+ </g>
+ </defs>
+ <use font-size="32" x="60" y="140" fill-opacity="1" fill="url(#LinearGrad-transparent)" xlink:href="#poem"/>
+ <rect x="60" y="217" width="360" height="15" fill="url(#LinearGrad-opaque)"/>
+ <rect x="15" y="217" width="450" height="15" fill="url(#LinearGrad-opaque)"/>
+ <text x="450" fill="#555" font-size="8" y="270" text-anchor="end">Frog Haiku by Matsuo Basho (1686), translated by Ross Figgins</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-204-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-204-t.svg
new file mode 100644
index 0000000000..b1c1c912b4
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-204-t.svg
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="ASl" desc="LinearGradient with only one stop-color" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: paint-grad-204-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Gradient with only one stop-color. This test is passed if the fill of
+ the rect on the right is identical to the fill of the rect on the left.
+ </p>
+ <p>
+ For gradients with only a single stop-color the painting shall occur
+ with the solid color fill using the color defined for the gradient stop.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-204-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <linearGradient x1="130" y1="50" x2="330" y2="250" xml:id="MyGradient" gradientUnits="userSpaceOnUse">
+ <stop stop-color="#F60" stop-opacity="0.5"/>
+ </linearGradient>
+ </defs>
+
+ <rect fill="url(#MyGradient)" stroke="black" stroke-width="2" x="60" y="60" width="150" height="150"/>
+ <text x="40" y="230">Gradient with one stop</text>
+
+ <rect fill="#F60" fill-opacity="0.5" stroke="black" stroke-width="2" x="270" y="60" width="150" height="150"/>
+ <text x="300" y="230">Reference</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-205-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-205-t.svg
new file mode 100644
index 0000000000..87ffaa898e
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-grad-205-t.svg
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="ASl" desc="LinearGradient with no stop-color" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: paint-grad-205-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Gradient with no stop-elements. The painting shall occur as if 'none' were specified
+ as the paint style, thus allowing the pale blue rectangle to be seen inside the square.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-grad-205-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <defs>
+ <linearGradient x1="130" y1="50" x2="330" y2="250" xml:id="MyGradient" gradientUnits="userSpaceOnUse" />
+ </defs>
+ <rect width="300" height="100" x="80" y="100" fill="#6CF"/>
+ <rect fill="url(#MyGradient)" stroke="black" stroke-width="2" x="130" y="50" width="200" height="200"/>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-other-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-other-201-t.svg
new file mode 100644
index 0000000000..f3890fe48b
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-other-201-t.svg
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="AE" desc="Test solidColor paint server." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: paint-other-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test solidColor paint server with 'solid-opacity' attribute.</p>
+ <p>
+ There are three 'solidColor' definitions - red, green, blue.
+ These are used for both the fill and outlines of the rectangle and circle.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-other-201-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g text-anchor="middle" font-size="10" fill="#555">
+ <text xml:id="display-title" x="240" y="30" font-size="14" fill="#000">Solid Color Paint Server</text>
+ <text xml:id="comment-1" x="240" y="45">
+ There are three 'solidColor' definitions - red, green, blue.
+ </text>
+ <text xml:id="comment-2" x="240" y="57">
+ These are used for both the fill and outlines of the rectangle and circle.
+ </text>
+ </g>
+ <defs>
+ <solidColor xml:id="solidRed" solid-color="red"/>
+ <solidColor xml:id="solidGreen" solid-color="green"/>
+ <solidColor xml:id="solidBlue" solid-color="blue"/>
+ </defs>
+ <g transform="scale(0.85),translate(43,40)">
+ <rect x="190" y="50" width="180" height="220" fill="url(#solidRed)" stroke="url(#solidBlue)" stroke-width="12"/>
+ <circle cx="190" cy="160" r="80" fill="none" stroke="url(#solidGreen)" stroke-width="20"/>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-01-t.svg
new file mode 100644
index 0000000000..cdc8479da7
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-01-t.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="KMC" desc="Test that viewer has the basic capability to handle the 'stroke' and 'stroke-width' properties." status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: paint-stroke-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Verify the basic capability to handle the stroke properties ("stroke") in combination with the "rect" element. The
+ pair should be rendered as two blue rectangles, the upper one without a stroke and the lower with a red stroke.
+ </p>
+ <p>The rendered picture should match the reference image, except for possible variations in the labeling text (per CSS2 rules).</p>
+ <p>
+ The test uses the "rect" element, as well as basic "fill" (solid primary colors), "stroke", stroke="red",
+ "font-family" (Arial) and "font-size" attributes.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-stroke-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- ============================================================================= -->
+ <!-- Draw two simple rectangles. One without stroke other with stroke:red -->
+ <!-- ============================================================================= -->
+ <text font-size="36" x="10" y="40">Basic paint: stroke properties.</text>
+ <rect xml:id="stroke-01" fill="blue" stroke="none" x="90" y="70" width="300" height="50" />
+ <rect xml:id="stroke-02" fill="blue" stroke-width="20" stroke="red" x="90" y="190" width="300" height="50" />
+ <text font-size="40" x="140" y="150">stroke="none"</text>
+ <text font-size="40" x="148" y="280">stroke="red"</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-02-t.svg
new file mode 100644
index 0000000000..23741b11f0
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-02-t.svg
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="KMC" desc="Test that viewer has the basic capability to handle the 'stroke', 'stroke-width' and 'stroke-linejoin' properties." status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: paint-stroke-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Verify the basic capability to handle the stroke properties ("stroke", "stroke-width", "stroke-linejoin") in
+ combination with the "rect" element. The pair should be rendered as two red rectangles without an interior fill.
+ The upper rectangle should have a stroke width of 5 with sharp corners. The lower rectangle should have a stroke
+ width of 5 with round corners.
+ </p>
+ <p>
+ The test uses the "rect" element, as well as basic "fill" (solid primary colors), "stroke", stroke="red"
+ stroke-width="10" stroke-linejoin="round", "font-family" (Arial) and "font-size" properties.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-stroke-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- ====================================================================== -->
+ <!-- Set of rectangles with stroke-width:10 and stroke-linejoin:round-->
+ <!-- ====================================================================== -->
+ <text font-size="36" x="10" y="40">Basic paint: stroke properties.</text>
+ <rect xml:id="stroke-01" fill="none" stroke="red" stroke-width="20" x="90" y="70" width="300" height="50" />
+ <rect xml:id="stroke-02" fill="none" stroke="red" stroke-width="20" stroke-linejoin="round" x="90" y="190" width="300" height="50" />
+ <text font-size="40" x="120" y="160">stroke-width="20"</text>
+ <text font-size="40" x="58" y="290">stroke-linejoin="round"</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-03-t.svg
new file mode 100644
index 0000000000..5e0a5bb718
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-03-t.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="KMC" desc="Test that viewer has the basic capability to handle the &lt;stroke properties&gt;" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: paint-stroke-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Verify the basic capability to handle the stroke properties ("stroke", "stroke-width" "stroke-linejoin", "stroke-linecap",
+ "stroke-miter") in combination with straight-line path commands. The pair should be rendered as as two red line segments.
+ The upper segment should have round end caps. The lower segment should be chopped off where the two line segments meet.
+ </p>
+ <p>
+ The test uses the "path" element, as well as basic "fill" (solid primary colors), "stroke", "stroke-width",
+ "stroke-linejoin", "stroke-linecap", "stroke-miter", "font-family" (Arial) and "font-size" properties.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-stroke-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- ====================================================================== -->
+ <!-- Test stroke-linecap:round and stroke-miterlimit:1 -->
+ <!-- ====================================================================== -->
+ <text font-size="36" x="10" y="40">Basic paint: stroke properties.</text>
+ <path fill="none" stroke="red" stroke-width="30" stroke-linecap="round" d="M 160 70 l 200 20 l -200 20 " />
+ <path fill="none" stroke="red" stroke-width="30" stroke-linejoin="miter" stroke-miterlimit="1" d="M 160 190 l 200 20 l -200 20" />
+ <text font-size="40" x="60" y="160">stroke-linecap="round"</text>
+ <text font-size="40" x="130" y="280">stroke-miter="1"</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-04-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-04-t.svg
new file mode 100644
index 0000000000..eee5583e55
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-04-t.svg
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="KMC" desc="Test that viewer has the basic capability to handle the 'stroke', 'stroke-width', 'stroke-dasharray' and 'stroke-dashoffset' properties." status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: paint-stroke-04-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Verify the "stroke-dasharray" and "stroke-dashoffset" properties. Two lines are drawn, one red and one black.
+ Both have a "stroke-dasharray" of "10,10" giving a dashed appearance where the size of the gaps and the size of
+ the dash is equal. The help show this, the black line has a "stroke-dashoffset" so that the dashes in the black
+ line match up with the gaps in the red line.
+ </p>
+ <p>
+ The test uses the "path" element, "stroke", "stroke-width", "stroke-dasharray" and "stroke-dashoffset", "font-family"
+ (Arial) and "font-size" properties.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-stroke-04-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- ====================================================================== -->
+ <!-- Test stroke-dasharray and stroke-dashoffset -->
+ <!-- ====================================================================== -->
+ <text font-size="36" x="10" y="60">Basic paint: stroke properties.</text>
+ <path xml:id="stroke-7b" fill="none" stroke="red" stroke-width="25" stroke-dashoffset="0" stroke-dasharray="10,10" d="M 50 120 L 430 120" />
+ <path xml:id="stroke-7c" fill="none" stroke="black" stroke-width="25" stroke-dashoffset="10" stroke-dasharray="10,10" d="M 50 140 L 430 140" />
+ <text font-size="30" x="65" y="210">stroke-dasharray="10, 10"</text>
+ <text font-size="30" x="75" y="260">stroke-dashoffset="10"</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-05-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-05-t.svg
new file mode 100644
index 0000000000..48085f4ec0
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-05-t.svg
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events"
+ shape-rendering="geometricPrecision">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="BB" desc="Shows how a user agent may render thin strokes" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: paint-stroke-05-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ User agents may render graphical primitives with different levels of accurancy.
+ This test is aimed at determining how does a UA render thin strokes.
+ </p>
+ <p>
+ The test file contains a number of vertical and horizontal lines.
+ The stroke width of the vertical lines are increasing from left to right.
+ The stroke width of the horizontal lines are increasing from top to bottom.
+ The user should be able to see a smooth stroke width increment for the vertical and horizontal lines.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">painting-stroke-05-t.svg</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="20" x="240" y="30" text-anchor="middle">Rendering thin strokes</text>
+ <polyline points="030,50 030,300" stroke="black" stroke-width="0.001"/>
+ <polyline points="50,50 50,300" stroke="black" stroke-width="0.1"/>
+ <polyline points="70,50 70,300" stroke="black" stroke-width="0.2"/>
+ <polyline points="90,50 90,300" stroke="black" stroke-width="0.3"/>
+ <polyline points="110,50 110,300" stroke="black" stroke-width="0.4"/>
+ <polyline points="130,50 130,300" stroke="black" stroke-width="0.5"/>
+ <polyline points="150,50 150,300" stroke="black" stroke-width="0.6"/>
+ <polyline points="170,50 170,300" stroke="black" stroke-width="0.7"/>
+ <polyline points="190,50 190,300" stroke="black" stroke-width="0.8"/>
+ <polyline points="210,50 210,300" stroke="black" stroke-width="0.9"/>
+ <polyline points="230,50 230,300" stroke="black" stroke-width="1.0"/>
+ <polyline points="250,50 250,300" stroke="black" stroke-width="1.1"/>
+ <polyline points="270,50 270,300" stroke="black" stroke-width="1.2"/>
+ <polyline points="290,50 290,300" stroke="black" stroke-width="1.3"/>
+ <polyline points="310,50 310,300" stroke="black" stroke-width="1.4"/>
+ <polyline points="330,50 330,300" stroke="black" stroke-width="1.5"/>
+ <polyline points="350,50 350,300" stroke="black" stroke-width="1.6"/>
+ <polyline points="370,50 370,300" stroke="black" stroke-width="1.7"/>
+ <polyline points="390,50 390,300" stroke="black" stroke-width="1.8"/>
+ <polyline points="410,50 410,300" stroke="black" stroke-width="1.9"/>
+ <polyline points="430,50 430,300" stroke="black" stroke-width="2.0"/>
+ <polyline points="450,50 450,300" stroke="black" stroke-width="2.1"/>
+
+ <line x1="10" x2="470" y1="100" y2="100" stroke="rgb(0,0,139)" stroke-width="0.1"/>
+ <line x1="10" x2="470" y1="150" y2="150" stroke="rgb(0,0,139)" stroke-width="0.5"/>
+ <line x1="10" x2="470" y1="200" y2="200" stroke="rgb(0,0,139)" stroke-width="1"/>
+ <line x1="10" x2="470" y1="250" y2="250" stroke="rgb(0,0,139)" stroke-width="2"/>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-06-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-06-t.svg
new file mode 100644
index 0000000000..23404c4918
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-06-t.svg
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="CN" desc="Test some effects of stroke-dasharray." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: paint-stroke-06-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test default effects of stroke-dasharray.
+ </p>
+ <p>
+ This specifically tests the values of none and 0.
+ This also tests an odd number of values in a dash-array attribute
+ and in combination with an offset.
+ </p>
+ <p>
+ The top two lines must be solid black. The next line shows a thick
+ black line with a thinner red line on top; both must have the same
+ dash pattern. The bottom two lines, one black and one blue, must render
+ so that the gaps of one correspond to the dashes of the other.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-stroke-06-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="scale(1.8)">
+
+ <!-- No dasharray -->
+ <path stroke="black" stroke-width="10" fill="none" stroke-dasharray="none" d=" M 20 20 L 200 20"/>
+
+ <path stroke="black" stroke-width="10" fill="none" stroke-dasharray="0" d=" M 20 40 L 200 40"/>
+
+ <!-- Odd number, should repeat to make an even number -->
+ <path stroke="black" stroke-width="20" fill="none" stroke-dasharray="5,2,5,5,2,5" d=" M 20 60 L 200 60"/>
+ <path stroke="red" stroke-width="10" fill="none" stroke-dasharray="5,2,5" d=" M 20 60 L 200 60"/>
+
+ <!-- Odd number, with a dashoffset test -->
+ <path stroke="black" stroke-width="10" fill="none" stroke-dasharray="2" d=" M 20 80 L 200 80"/>
+
+ <path stroke="blue" stroke-width="10" fill="none" stroke-dasharray="2" stroke-dashoffset="2" d="
+ M 20 90 L 200 90"/>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-07-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-07-t.svg
new file mode 100644
index 0000000000..2a41e6b396
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-07-t.svg
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="CN" desc="Test effect of different stroke-miterlimits." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: paint-stroke-07-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test effect of different stroke-miterlimits. For this particular combination of stroke width and angle,
+ the cut off value of stroke-miterlimit is 18.028. Thus, the first and second subtests should not truncate
+ the stroke, and all the rest must truncate it.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-stroke-07-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="scale(1.2) translate(60, 30)">
+ <!-- test different miterlimits -->
+ <path stroke="black" stroke-width="10" stroke-linejoin="miter" stroke-miterlimit="20" fill="none" d="M 20 20 L 200 30 L 20 40" />
+ <path stroke="black" stroke-width="10" stroke-linejoin="miter" stroke-miterlimit="18.1" fill="none" d="M 20 50 L 200 60 L 20 70" />
+ <path stroke="black" stroke-width="10" stroke-linejoin="miter" stroke-miterlimit="17.9" fill="none" d="M 20 80 L 200 90 L 20 100" />
+ <path stroke="black" stroke-width="10" stroke-linejoin="miter" stroke-miterlimit="17" fill="none" d="M 20 110 L 200 120 L 20 130" />
+ <path stroke="black" stroke-width="10" stroke-linejoin="miter" stroke-miterlimit="4" fill="none" d="M 20 140 L 200 150 L 20 160" />
+ <path stroke="black" stroke-width="10" stroke-linejoin="miter" stroke-miterlimit="1" fill="none" d="M 20 170 L 200 180 L 20 190" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-08-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-08-t.svg
new file mode 100644
index 0000000000..8de0746842
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-08-t.svg
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="CN" desc="Test effects of stroke-opacity range" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: paint-stroke-08-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test effects of stroke-opacity range. Values
+ outside the range 0-1.0 must be clamped.
+ </p>
+ <p>
+ There must be no blue bars visible beside the three pink dots.
+ Four semitransparent blue bars, increasingly more opaque,
+ must line up with the yellow dots. Three fully opaque
+ blue bars must line up with the green dots.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-stroke-08-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="translate(50, 0) scale(1.7)">
+ <circle r="5" fill="#f66" cx="200" cy="20"/>
+ <circle r="5" fill="#f66" cx="200" cy="40"/>
+ <circle r="5" fill="#f66" cx="200" cy="60"/>
+ <circle r="5" fill="#f66" cx="200" cy="80"/>
+ <circle r="5" fill="#ff0" cx="200" cy="80"/>
+ <circle r="5" fill="#ff0" cx="200" cy="100"/>
+ <circle r="5" fill="#ff0" cx="200" cy="120"/>
+ <circle r="5" fill="#ff0" cx="200" cy="140"/>
+ <circle r="5" fill="#6f3" cx="200" cy="160"/>
+ <circle r="5" fill="#6f3" cx="200" cy="180"/>
+ <circle r="5" fill="#6f3" cx="200" cy="200"/>
+ <!-- Test range and values outside range (should be clamped to valid range) -->
+ <path stroke="blue" stroke-width="10" fill="none" stroke-opacity="-1.0" d=" M 20 20 L 200 20"/>
+ <path stroke="blue" stroke-width="10" fill="none" stroke-opacity="-0.1" d=" M 20 40 L 200 40"/>
+ <path stroke="blue" stroke-width="10" fill="none" stroke-opacity="0.0" d=" M 20 60 L 200 60"/>
+ <path stroke="blue" stroke-width="10" fill="none" stroke-opacity="0.2" d=" M 20 80 L 200 80"/>
+ <path stroke="blue" stroke-width="10" fill="none" stroke-opacity="0.4" d=" M 20 100 L 200 100"/>
+ <path stroke="blue" stroke-width="10" fill="none" stroke-opacity="0.6" d=" M 20 120 L 200 120"/>
+ <path stroke="blue" stroke-width="10" fill="none" stroke-opacity="0.8" d=" M 20 140 L 200 140"/>
+ <path stroke="blue" stroke-width="10" fill="none" stroke-opacity="1.0" d=" M 20 160 L 200 160"/>
+ <path stroke="blue" stroke-width="10" fill="none" stroke-opacity="1.1" d=" M 20 180 L 200 180"/>
+ <path stroke="blue" stroke-width="10" fill="none" stroke-opacity="2.0" d=" M 20 200 L 200 200"/>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-202-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-202-t.svg
new file mode 100644
index 0000000000..3f8d53864f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-202-t.svg
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="DOH" desc="Direction of stroke-dasharray and stroke-dashoffset for basic shapes." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: paint-stroke-202-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Direction of stroke-dasharray and stroke-dashoffset for basic shapes.
+ </p>
+ <p>
+ The main indication for a failed test is the appearence of a blue path on
+ a white background area. It is passed, if all blue paths are on a gray background area.
+ </p>
+ <p>
+ stroke-dasharray and stroke-dashoffset are tested on basic shapes circle, ellipse, rectangle,
+ rectangle with rounded corners, line, polyline and polygon. The test is sensitive to the
+ direction of stroke-dasharray and stroke-dashoffset and on the starting point on the basic
+ shape.
+ </p>
+ <p>
+ The dashes are positioned correctly, if they are only on a gray background area.
+ If there are dashes on a white background, this is an indication for an error.
+ Additional information given in the elements title and desc for the related subtest
+ may help to identify the tested shape and property combination and the error,
+ if there is one.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-stroke-202-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g>
+ <title>background of filled rectangles indicating stroking areas in gray</title>
+ <rect x="0" y="0" width="480" height="360" fill="#fff" />
+ <rect x="20" y="20" width="100" height="100" fill="#ccc" />
+ <rect x="120" y="120" width="100" height="100" fill="#ccc" />
+ <g transform="translate(0,30) rotate(45,320,120)">
+ <rect x="220" y="20" width="100" height="100" fill="#ccc" />
+ <rect x="320" y="120" width="100" height="100" fill="#ccc" />
+ </g>
+ <rect x="400" y="40" width="70" height="70" fill="#ccc" />
+ <rect x="400" y="180" width="70" height="70" fill="#ccc" />
+ </g>
+
+ <g>
+ <title>testing stroke-dasharray for circle, rectangle with rounded corners, ellipse</title>
+ <circle cx="120" cy="120" r="89.1268"
+ fill="none" stroke-width="20" stroke="#00f" stroke-dasharray="140">
+ <title>stroke-dasharray on circle without stroke-dashoffset</title>
+ <desc>Note that the pathLength of the circle is exactly 560</desc>
+ </circle>
+ <rect x="30.8732" y="30.8732" width="178.2535" height="178.2535" rx="200"
+ fill="none" stroke-width="12" stroke="#00a" stroke-dasharray="0,140,140,140,140">
+ <title>stroke-dasharray on rect with rounded corners without stroke-dashoffset</title>
+ <desc>Note that the pathLength of the rect is exactly 560</desc>
+ </rect>
+ <ellipse cx="120" cy="120" rx="89.1268" ry="89.1268"
+ fill="none" stroke-width="4" stroke="#44f" stroke-dasharray="140">
+ <title>stroke-dasharray on ellipse without stroke-dashoffset</title>
+ <desc>Note that the pathLength of the ellipse is exactly 560</desc>
+ </ellipse>
+
+
+ <circle cx="320" cy="150" r="89.1268"
+ fill="none" stroke-width="20" stroke="#00f" stroke-dasharray="140" stroke-dashoffset="-70">
+ <title>stroke-dasharray on circle without negative stroke-dashoffset</title>
+ <desc>Note that the pathLength of the circle is exactly 560</desc>
+ </circle>
+ <rect x="230.8732" y="60.8732" width="178.2535" height="178.2535" rx="200"
+ fill="none" stroke-width="12" stroke="#00a" stroke-dasharray="140" stroke-dashoffset="-210">
+ <title>stroke-dasharray on rect with rounded corners with negative stroke-dashoffset</title>
+ <desc>Note that the pathLength of the rect is exactly 560</desc>
+ </rect>
+ <ellipse cx="320" cy="150" rx="89.1268" ry="89.1268"
+ fill="none" stroke-width="4" stroke="#44f" stroke-dasharray="140" stroke-dashoffset="210">
+ <title>stroke-dasharray on ellipse with positive stroke-dashoffset</title>
+ <desc>Note that the pathLength of the ellipse is exactly 560</desc>
+ </ellipse>
+ </g>
+
+
+ <g fill="none" stroke-dasharray="none" stroke-dashoffset="none">
+ <title>testing stroke-dasharray for line, polyline, polygon</title>
+ <line x1="10" y1="250" x2="80" y2="250" stroke-width="30" stroke="#ccc" />
+ <line x1="150" y1="250" x2="220" y2="250" stroke-width="30" stroke="#ccc" />
+ <line x1="10" y1="250" x2="220" y2="250"
+ stroke-width="20" stroke="#00f" stroke-dasharray="70" stroke-dashoffset="0">
+ <title>stroke-dasharray on line with stroke-dashoffset set to 0</title>
+ </line>
+ <polyline points="10,250 100,250 220,250"
+ stroke-width="12" stroke="#00a" stroke-dasharray="70" stroke-dashoffset="0">
+ <title>stroke-dasharray on polyline with stroke-dashoffset set to 0</title>
+ </polyline>
+ <polygon points="10,250 100,250 255,250"
+ stroke-width="4" stroke="#44f" stroke-dasharray="70" stroke-dashoffset="0">
+ <title>stroke-dasharray on polygon with stroke-dashoffset set to 0</title>
+ </polygon>
+
+ <line x1="10" y1="290" x2="45" y2="290" stroke-width="30" stroke="#ccc" />
+ <line x1="115" y1="290" x2="185" y2="290" stroke-width="30" stroke="#ccc" />
+ <line x1="255" y1="290" x2="290" y2="290" stroke-width="30" stroke="#ccc" />
+ <line x1="10" y1="290" x2="290" y2="290" stroke-width="20" stroke="#00f" stroke-dasharray="70" stroke-dashoffset="35">
+ <title>stroke-dasharray on line with stroke-dashoffset</title>
+ </line>
+ <polyline points="10,290 100,290 290,290"
+ stroke-width="12" stroke="#00a" stroke-dasharray="70" stroke-dashoffset="-105">
+ <title>stroke-dasharray on polyline with negative stroke-dashoffset</title>
+ </polyline>
+ <polygon points="10,290 100,290 290,290"
+ stroke-width="4" stroke="#44f" stroke-dasharray="70" stroke-dashoffset="35">
+ <title>stroke-dasharray on polygon with stroke-dashoffset</title>
+ </polygon>
+ </g>
+
+
+ <g fill="none" >
+ <title>testing stroke-dasharray for rectangles</title>
+ <rect x="420" y="30" width="30" height="240"
+ stroke-width="20" stroke="#00f" stroke-dasharray="70" stroke-dashoffset="100">
+ <title>stroke-dasharray on rect with positive stroke-dashoffset</title>
+ </rect>
+
+ <rect x="420" y="20" width="30" height="258.5841" rx="10"
+ stroke-width="12" stroke="#00a"
+ stroke-dasharray="10,35.708,70,70,70,78.5841,70,70,70,70" stroke-dashoffset="10">
+ <title>stroke-dasharray on rect with rounded corners with positive stroke-dashoffset</title>
+ <desc>Note that the pathLength of the rectangle is exactly 560, the round parts are 2pi*rx</desc>
+ </rect>
+
+ <rect x="420" y="-10" width="30" height="350"
+ stroke-width="4" stroke="#44f" stroke-dasharray="0,70,70,70,70,210,70,70,70,70" stroke-dashoffset="-10">
+ <title>stroke-dasharray on rect with negative stroke-dashoffset</title>
+ </rect>
+ </g>
+
+
+ <g font-size="12" stroke="none" fill="#ccc">
+ <text x="340" y="310">position of the dashes:</text>
+ <text x="340" y="322">blue on gray: ok</text>
+ <text x="340" y="334">blue on white: fail </text>
+ </g>
+
+
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-204-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-204-t.svg
new file mode 100644
index 0000000000..fa32d3590b
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-204-t.svg
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="DOH" desc="Precision tests for stroke-linejoin" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: paint-stroke-204-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Precision tests for stroke-linejoin.
+ </p>
+ <p>
+ The main indication for a failed test is the appearence of something red.
+ </p>
+ <p>
+ stroke-linejoin is tested, using a comparsion with filled or stroked paths or shapes with the same appearance.
+ This is tested for different three miter angles for the values round, miter and bevel, for each of them one with
+ test path on top of the comparsion shapes and one with the path below.
+ </p>
+ The four paths top right test the inheritance either for the value explicitely set to 'inherit' or a missing stroke-linejoin property.
+ <p>
+ </p>
+ <p>
+ The top is always blue. If something
+ red gets visible, an error is occured.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-stroke-204-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <rect x="0" y="0" width="480" height="360" fill="#fff" />
+ <g stroke-linejoin="miter" stroke-miterlimit="10">
+ <g transform="translate(-25,-25) scale(0.75)">
+ <title>stroke-linejoin round (on top)</title>
+ <path d="M50,50L50,100 M50,100 100,100" stroke-width="20" stroke="red" fill="none"/>
+ <circle cx="50" cy="100" r="10" fill="red" />
+ <path d="M50,50L50,100 100,100" stroke-width="20" stroke-linejoin="round" stroke="blue" fill="none"/>
+
+ <path d="M200,50L150,100 M150,100 200,100" stroke-width="20" stroke="red" fill="none"/>
+ <circle cx="150" cy="100" r="10" fill="red" />
+ <path d="M200,50L150,100 200,100" stroke-width="20" stroke-linejoin="round" stroke="blue" fill="none"/>
+
+ <path d="M250,50L300,100 M300,100 350,100" stroke-width="20" stroke="red" fill="none"/>
+ <circle cx="300" cy="100" r="10" fill="red" />
+ <path d="M250,50L300,100 350,100" stroke-width="20" stroke-linejoin="round" stroke="blue" fill="none"/>
+ </g>
+
+ <g transform="translate(-25,35) scale(0.75)">
+ <title>stroke-linejoin round (below)</title>
+ <path d="M50,50L50,100 100,100" stroke-width="20" stroke-linejoin="round" stroke="red" fill="none"/>
+ <path d="M50,50L50,100 M50,100 100,100" stroke-width="20" stroke="blue" fill="none"/>
+ <circle cx="50" cy="100" r="10" fill="blue" />
+
+ <path d="M200,50L150,100 200,100" stroke-width="20" stroke-linejoin="round" stroke="red" fill="none"/>
+ <path d="M200,50L150,100 M150,100 200,100" stroke-width="20" stroke="blue" fill="none"/>
+ <circle cx="150" cy="100" r="10" fill="blue" />
+
+ <path d="M250,50L300,100 350,100" stroke-width="20" stroke-linejoin="round" stroke="red" fill="none"/>
+ <path d="M250,50L300,100 M300,100 350,100" stroke-width="20" stroke="blue" fill="none"/>
+ <circle cx="300" cy="100" r="10" fill="blue" />
+ </g>
+
+
+
+ <g transform="translate(-25,120) scale(0.75)">
+ <title>stroke-linejoin miter (on top)</title>
+
+ <path d="M50,50L50,110 M40,100 100,100" stroke-width="20" stroke="red" fill="none"/>
+ <path d="M50,50L50,100 100,100" stroke-width="20" stroke-linejoin="miter" stroke="blue" fill="none"/>
+
+ <path d="M192.928932188,42.928932188
+ L125.857864376,110 200,110 200,90 174.142135624,90 207.071067812,57.071067812z" fill="red"/>
+ <path d="M200,50L150,100 200,100" stroke-width="20" stroke-linejoin="miter" stroke="blue" fill="none"/>
+
+ <path d="M242.928932188,57.071067812
+ L295.857864376,110 350,110 350,90 304.142135624,90 257.071067812,42.928932188z" fill="red"/>
+ <path d="M250,50L300,100 350,100" stroke-width="20" stroke-linejoin="miter" stroke="blue" fill="none"/>
+ </g>
+
+ <g transform="translate(-25,180) scale(0.75)">
+ <title>stroke-linejoin miter (below)</title>
+ <path d="M50,50L50,100 100,100" stroke-width="20" stroke-linejoin="miter" stroke="red" fill="none"/>
+ <path d="M50,50L50,110 M40,100 100,100" stroke-width="20" stroke="blue" fill="none"/>
+
+ <path d="M200,50L150,100 200,100" stroke-width="20" stroke-linejoin="miter" stroke="red" fill="none"/>
+ <path d="M192.928932188,42.928932188
+ L125.857864376,110 200,110 200,90 174.142135624,90 207.071067812,57.071067812z" fill="blue"/>
+
+ <path d="M250,50L300,100 350,100" stroke-width="20" stroke-linejoin="miter" stroke="red" fill="none"/>
+ <path d="M242.928932188,57.071067812
+ L295.857864376,110 350,110 350,90 304.142135624,90 257.071067812,42.928932188z" fill="blue"/>
+ </g>
+
+
+ <g transform="translate(215,-25) scale(0.75)">
+ <title>stroke-linejoin bevel (on top)</title>
+
+ <path d="M40,50L40,100 50,110 100,110 100,90 60,90 60,50z" fill="red"/>
+ <path d="M50,50L50,100 100,100" stroke-width="20" stroke-linejoin="bevel" stroke="blue" fill="none"/>
+
+ <path d="M192.928932188,42.928932188
+ L142.928932188,92.928932188 150,110
+ 200,110 200,90 174.142135624,90 207.071067812,57.071067812z" fill="red"/>
+ <path d="M200,50L150,100 200,100" stroke-width="20" stroke-linejoin="bevel" stroke="blue" fill="none"/>
+
+ <path d="M242.928932188,57.071067812
+ L292.928932188,107.071067812 300,110
+ 350,110 350,90 304.142135624,90 257.071067812,42.928932188z" fill="red"/>
+ <path d="M250,50L300,100 350,100" stroke-width="20" stroke-linejoin="bevel" stroke="blue" fill="none"/>
+ </g>
+
+ <g transform="translate(215,35) scale(0.75)">
+ <title>stroke-linejoin bevel (below)</title>
+ <path d="M50,50L50,100 100,100" stroke-width="20" stroke-linejoin="bevel" stroke="red" fill="none"/>
+ <path d="M40,50L40,100 50,110 100,110 100,90 60,90 60,50z" fill="blue"/>
+
+ <path d="M200,50L150,100 200,100" stroke-width="20" stroke-linejoin="bevel" stroke="red" fill="none"/>
+ <path d="M192.928932188,42.928932188
+ L142.928932188,92.928932188 150,110 200,110 200,90 174.142135624,90 207.071067812,57.071067812z" fill="blue"/>
+
+ <path d="M250,50L300,100 350,100" stroke-width="20" stroke-linejoin="bevel" stroke="red" fill="none"/>
+ <path d="M242.928932188,57.071067812
+ L292.928932188,107.071067812 300,110 350,110 350,90 304.142135624,90 257.071067812,42.928932188z" fill="blue"/>
+ </g>
+
+ <g transform="translate(250,140)" stroke-linejoin="round" stroke="blue" fill="none" stroke-width="10">
+ <title>inheritance test (on top, round)</title>
+ <path d="M0,150L25,120 50,150" stroke-linejoin="round" stroke="red" fill="none" stroke-width="10" />
+ <path d="M1000,0L1000,0" stroke-linejoin="miter" />
+ <path d="M0,150L25,120 50,150" stroke-linejoin="inherit" />
+
+ <path d="M0,0L100,200 50,0" stroke-linejoin="round" stroke="red" fill="none" stroke-width="10" />
+ <path d="M0,0L100,200 50,0" />
+ </g>
+
+ <g transform="translate(370,140)" stroke-linejoin="round" stroke="red" fill="none" stroke-width="10">
+ <title>inheritance test (below, round)</title>
+ <path d="M1000,0L1000,0" stroke-linejoin="miter" />
+ <path d="M0,150L25,120 50,150" stroke-linejoin="inherit" />
+ <path d="M0,150L25,120 50,150" stroke-linejoin="round" stroke="blue" fill="none" stroke-width="10" />
+
+ <path d="M0,0L100,200 50,0" />
+ <path d="M0,0L100,200 50,0" stroke-linejoin="round" stroke="blue" fill="none" stroke-width="10" />
+ </g>
+ </g>
+ <g font-size="12" stroke="none" fill="#ccc">
+ <text x="20" y="283">stroke-linejoin:</text>
+ <text x="20" y="295">red = wrong</text>
+ </g>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-207-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-207-t.svg
new file mode 100644
index 0000000000..9599d36ccb
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-stroke-207-t.svg
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="DOH" desc="Centering of stroke on the outline of rectangles." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: paint-stroke-207-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Centering of stroke on the outline of rectangles.
+ </p>
+ <p>
+ The main indication for a failed test is the appearence of something red.
+ </p>
+ <p>
+ The width and position of the stroke centered on the outline of a rectangle is tested with four stroked rectangles,
+ one is the thin black stroked test frame rectangle, the second one a large blue rectangle, the third a rectangle
+ with rounded corners, looking like a circle and the fourth a small square.
+ </p>
+ <p>
+ The correct position is tested by a comparsion with several filled rectangles in the background or in the fourth case
+ covering the test square completely. The parts of the background covered with the blue test rectangles are filled red,
+ respectively the test square is stroked red too.
+ Therefore if something red gets visible, the position of the stroke of
+ the related test rectangle is wrong.
+ </p>
+ <p>
+ According to the conformance criteria all visual rendering should be accurate to within one px unit to the mathematically
+ correct result. Therefore possible residuals from the red background parts have to be in this
+ range of accuracy to pass the test.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-stroke-207-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <g>
+ <title>background of filled rectangles indicating the position of the stroked test rectangles</title>
+ <rect x="0" y="0" width="480" height="360" fill="#fff" />
+ <rect x="0.5" y="0.5" width="479" height="359" fill="#f00" />
+ <rect x="1.5" y="1.5" width="477" height="357" fill="#fff" />
+ <rect x="60" y="40" width="360" height="240" fill="#f00" />
+ <rect x="80" y="60" width="320" height="200" fill="#fff" />
+ <rect x="119.6" y="109.6" width="100.8" height="100.8" rx="200" fill="#f00" />
+ <rect x="140.4" y="130.4" width="59.2" height="59.2" ry="200" fill="#fff" />
+ <rect x="260" y="110" width="100" height="100" fill="#a00" />
+ <rect x="280" y="130" width="60" height="60" fill="#fff" />
+ </g>
+ <g stroke="#00f" stroke-width="20" fill="none">
+ <rect x="70" y="50" width="340" height="220">
+ <title>large blue stroked test rectangle</title>
+ </rect>
+ <rect x="130" y="120" width="80" height="80" ry="40" rx="40" stroke-width="20.8">
+ <title>small blue stroked test rectangle with rounded corners looking like a circle</title>
+ </rect>
+ </g>
+
+
+
+ <rect x="270" y="120" width="80" height="80" stroke="#f00" stroke-width="20" fill="none">
+ <title>small red stroked test rectangle</title>
+ </rect>
+ <g stroke="none" fill="#00f">
+ <title>small blue rectangles to cover the small red stroked test rectangle</title>
+ <rect x="260" y="110" width="80" height="20" />
+ <rect x="340" y="110" width="20" height="80" />
+ <rect x="280" y="190" width="80" height="20" />
+ <rect x="260" y="130" width="20" height="80" />
+ </g>
+
+
+ <g font-size="12" stroke="none" fill="#ccc">
+ <text x="340" y="315">position of the stroke:</text>
+ <text x="340" y="328">red = wrong</text>
+ </g>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-vfill-202-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-vfill-202-t.svg
new file mode 100644
index 0000000000..b316a3435f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-vfill-202-t.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events"
+ viewport-fill="yellow" viewport-fill-opacity="0.5">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ASl" desc="Viewport-fill on transparent image" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: paint-vfill-202-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Tests viewport-fill and viewport-fill-opacity.
+ The image should show the correct viewport-fill (green).
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-vfill-202-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <rect x="1" y="90" width="478" height="180" stroke="black" fill="red" fill-opacity="0.3"/>
+ <image xlink:href="../images/viewport-fill-img.png" x="64" y="64" width="104" height="112" transform="scale(0.5) translate(-32, -32)" viewport-fill="green"/>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-vfill-204-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-vfill-204-t.svg
new file mode 100644
index 0000000000..f57b6974e2
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-vfill-204-t.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events"
+ viewport-fill="yellow" viewport-fill-opacity="0.0">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ASl" desc="Viewport fill and opacity inheritance" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: paint-vfill-204-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test on viewport-fill and viewport-fill-opacity. viewport-fill-opacity is set to 0.0 so the set viewport-fill
+ color should not be visible. The image has its viewport-fill set to "inherit" and viewport-fill-opacity to 1.0
+ so the image should show with a yellow viewport-fill and full opacity.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-vfill-204-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18" viewport-fill="inherit">
+ <rect x="1" y="90" width="478" height="180" stroke="black" fill="red" fill-opacity="0.3"/>
+ <image xlink:href="../images/viewport-fill-img.png" x="64" y="64" width="104" height="112" viewport-fill="inherit" viewport-fill-opacity="1.0"/>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-vfill-205-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-vfill-205-t.svg
new file mode 100644
index 0000000000..a5fdddf48a
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paint-vfill-205-t.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events"
+ viewport-fill="yellow" viewport-fill-opacity="0.5">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ASl" desc="Viewport fill and opacity" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: paint-vfill-205-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Tests viewport-fill and viewport-fill-opacity.
+ Output should match reference image.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paint-vfill-205-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <rect x="1" y="90" width="478" height="180" stroke="black" fill="red" fill-opacity="0.3"/>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-01-t.svg
new file mode 100644
index 0000000000..f7fb68e9ed
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-01-t.svg
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN,AE" owner="LH" desc="Test that the viewer has the basic capability to handle the 'path' element and data (d) attribute in combination with the cubic Bezier curveto, both regular and shorthand/smooth forms - C, c, S, s (along with Mm and Zz)." status="accepted"
+ approved="yes"
+ version="$Revision: 1.13 $" testname="$RCSfile: paths-data-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test that the viewer has the basic capability to handle the 'path' element and its data (d) attribute in combination with the cubic Bezier curveto commands, C, c, S, s (plus Mm and Zz).</p>
+ <p>There are 8 subtests, each composed from the cubic Bezier path commands per the label by the subtest. On-curve control points (i.e., the curve position) are marked by small blue squares. Subtests are filled, or stroked, or both, using simple style properties and colors.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansISO-8859-1" unicode-range="U+0-FF">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans-ISO-8859-1.svg#iso_8859_1" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansISO-8859-1,sans-serif" font-size="18">
+ <!-- ====================================================================== -->
+ <!-- First Curve "X" that has subpath utilizing M, C, S, m, c, & s ======== -->
+ <!-- ====================================================================== -->
+ <text font-size="12" x="240" y="14" text-anchor="middle">Cubic bézier curves drawn with commands:</text>
+ <path xml:id="X_curve_MCSmcs" fill="#FF0000" stroke="#00C000" d=" M 210 130 C 145 130 110 80 110 80 S 75 25 10 25 m 0 105 c 65 0 100 -50 100 -50 s 35 -55 100 -55 " />
+ <!-- ====================================================================== -->
+ <!-- Markers for path control points ===================================== -->
+ <!-- ====================================================================== -->
+ <rect x="208" y="128" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="108" y="78" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="8" y="23" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="8" y="128" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="108" y="78" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="208" y="23" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <text font-size="12" x="5" y="82">M,C,S,m,c,s</text>
+ <!-- ====================================================================== -->
+ <!-- Infinity using M, c, c, c, C & z ===================================== -->
+ <!-- ====================================================================== -->
+ <path xml:id="Infinity_McccCz" fill="none" stroke="#000000" d=" M 240 90 c 0 30 7 50 50 0 c 43 -50 50 -30 50 0 c 0 83 -68 -34 -90 -30 C 240 60 240 90 240 90 z " />
+ <!-- ====================================================================== -->
+ <!-- Markers for path control points ====================================== -->
+ <!-- ====================================================================== -->
+ <rect x="238" y="88" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="288" y="88" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="338" y="88" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="248" y="58" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <text font-size="12" x="253" y="50">M,c,c,c,C,z</text>
+ <!-- ====================================================================== -->
+ <!-- Horizontal line utilizing M, C & Z =================================== -->
+ <!-- ====================================================================== -->
+ <path xml:id="Line_MCZ" fill="none" stroke="#000000" d="M80 170 C100 170 160 170 180 170Z" />
+ <!-- ====================================================================== -->
+ <!-- Markers for path control points ====================================== -->
+ <!-- ====================================================================== -->
+ <rect x="78" y="168" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="178" y="168" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <text font-size="12" x="110" y="190">M,C,Z</text>
+ <!-- ====================================================================== -->
+ <!-- Inverted V using M, C, c & Z ========================================= -->
+ <!-- ====================================================================== -->
+ <path xml:id="Inv_V_MCcZ" fill="#00C000" stroke="none" d="M5 260 C40 260 60 175 55 160 c -5 15 15 100 50 100Z" />
+ <!-- ====================================================================== -->
+ <!-- Markers for path control points ====================================== -->
+ <!-- ====================================================================== -->
+ <rect x="3" y="258" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="53" y="158" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="103" y="258" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <text font-size="12" x="85" y="220">M,C,c,Z</text>
+ <!-- ====================================================================== -->
+ <!-- Remembrance Ribbon using m, c & s ==================================== -->
+ <!-- ====================================================================== -->
+ <path xml:id="Rem_Rib_mcs" fill="none" stroke="#000000" d="m 200 260 c 50 -40 50 -100 25 -100 s -25 60 25 100 " />
+ <!-- ====================================================================== -->
+ <!-- Markers for path control points ====================================== -->
+ <!-- ====================================================================== -->
+ <rect x="198" y="258" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="223" y="158" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="248" y="258" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <text font-size="12" x="165" y="210">m,c,s</text>
+ <!-- ====================================================================== -->
+ <!-- 90 degree arc using M & C ============================================ -->
+ <!-- ====================================================================== -->
+ <path xml:id="Arc_MC" fill="#0000FF" stroke="#000000" d=" M 360 100 C 420 90 460 140 450 190" />
+ <!-- ====================================================================== -->
+ <!-- Markers for path control points ====================================== -->
+ <!-- ====================================================================== -->
+ <rect x="358" y="98" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="448" y="188" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <text font-size="12" x="360" y="150">M,C</text>
+ <!-- ====================================================================== -->
+ <!-- Circle using M, c, s, s, s & z ======================================= -->
+ <!-- ====================================================================== -->
+ <path xml:id="Circle_Mcssz" fill="#FFFF00" stroke="#000000" d="M360 210 c 0 20 -16 36 -36 36 s -36 -16 -36 -36 s 16 -36 36 -36 s 36 16 36 36 z " />
+ <!-- ====================================================================== -->
+ <!-- Markers for path control points ====================================== -->
+ <!-- ====================================================================== -->
+ <rect x="358" y="208" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="322" y="244" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="286" y="208" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="322" y="172" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <text font-size="12" x="290" y="265">M,c,s,s,s,z</text>
+ <!-- ====================================================================== -->
+ <!-- Inverted horseshoe using m, c & z ==================================== -->
+ <!-- ====================================================================== -->
+ <path xml:id="Horseshoe_Mcs" fill="#F0F0F0" stroke="#FF0000" d="m 360 325 c -40 -60 95 -100 80 0 z " />
+ <!-- ====================================================================== -->
+ <!-- Markers for path control points ====================================== -->
+ <!-- ====================================================================== -->
+ <rect x="358" y="323" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <rect x="438" y="323" width="4" height="4" fill="#4A83FF" stroke="none" />
+ <text font-size="12" x="380" y="340">m,c,z</text>
+ </g>
+ <g font-family="SVGFreeSansISO-8859-1,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.13 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansISO-8859-1,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-02-t.svg
new file mode 100644
index 0000000000..7e39904794
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-02-t.svg
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN,AE" owner="LH" desc="Test that the viewer has the basic capability to handle the 'path' element and data (d) attribute in combination with the quadratic Bezier curveto commands, both regular and shorthand/smooth forms - Q, q, T, t (along with Mm and Zz)." status="accepted"
+ approved="yes"
+ version="$Revision: 1.13 $" testname="$RCSfile: paths-data-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test that the viewer has the basic capability to handle the 'path' element and its data (d) attribute in combination with the quadratic Bezier curveto commands, Q, q, T, t (plus Mm and Zz).</p>
+ <p>There are 7 subtests, each composed from the quadric Bezier path commands per the label by the subtest. On-curve control points (i.e., the curve position) are marked by small colored squares. Subtests are filled, or stroked, or both, using simple style properties and colors.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansISO-8859-1" unicode-range="U+0-FF">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans-ISO-8859-1.svg#iso_8859_1" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansISO-8859-1,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Quadratic bézier curves drawn with commands:</text>
+ <!-- ====================================================================== -->
+ <!-- Quad Bezier with sub-path using M, Q, M, q, & z ====================== -->
+ <!-- ====================================================================== -->
+ <path xml:id="Bez_MQMqz" fill="none" stroke="#0000FF" stroke-width="3" d="M 15 20 Q 30 120 130 30 M 180 80 q -75 -100 -163 -60z" />
+ <text font-size="12" x="80" y="86">M,Q,M,q,z</text>
+ <rect x="13" y="18" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="128" y="28" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="178" y="78" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="15" y="18" width="4" height="4" fill="#00C000" stroke="none" />
+ <!-- ====================================================================== -->
+ <!-- Quad Bezier with sub-path using m, q, z, m, q, & z =================== -->
+ <!-- ====================================================================== -->
+ <path xml:id="Bez_fill_MQzmqz" fill="#FFFF00" stroke="#CF0000" d="M372 130Q272 50 422 10zm70 0q50-150-80-90z" />
+ <text font-size="12" x="352" y="150">m,q,z,m,q,z</text>
+ <rect x="370" y="128" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="420" y="8" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="440" y="128" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="360" y="38" width="4" height="4" fill="#0000FF" stroke="none" />
+ <!-- ====================================================================== -->
+ <!-- Simple Bezier using M, Q, & Z ======================================== -->
+ <!-- ====================================================================== -->
+ <path xml:id="Bez_stroke_MQz" fill="none" stroke="#00FFFF" d="M224 103Q234 -12 304 33Z" />
+ <text font-size="12" x="192" y="36">M,Q,Z</text>
+ <rect x="222" y="101" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="302" y="31" width="4" height="4" fill="#0000FF" stroke="none" />
+ <!-- ====================================================================== -->
+ <!-- Tri Bezier using M, Q, T, Q, & z ===================================== -->
+ <!-- ====================================================================== -->
+ <path xml:id="Tri_MQTQz" fill="#00C000" stroke="#000000" d="M208 168Q258 268 308 168T258 118Q128 88 208 168z" />
+ <text font-size="12" x="308" y="188">M,Q,T,Q,z</text>
+ <rect x="206" y="166" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="306" y="166" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="256" y="116" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="206" y="206" width="4" height="4" fill="#0000FF" stroke="none" />
+ <!-- ====================================================================== -->
+ <!-- Double Bezier using M, Q, Q, & z ===================================== -->
+ <!-- ====================================================================== -->
+ <path xml:id="Inv_V_MCcZ" fill="#CF0000" stroke="none" d=" M 60 100 Q -40 150 60 200 Q 160 150 60 100 z " />
+ <text font-size="12" x="80" y="200">M,Q,Q,z</text>
+ <rect x="58" y="98" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="58" y="198" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="58" y="98" width="4" height="4" fill="#0000FF" stroke="none" />
+ <!-- ====================================================================== -->
+ <!-- Sin Wave using M, q, t, t, t, t, & z ================================ -->
+ <!-- ====================================================================== -->
+ <path xml:id="Sin_Mqttttz" fill="none" stroke="#FF0000" d="M240 296q25-100 47 0t47 0t47 0t47 0t47 0z" />
+ <text font-size="12" x="380" y="236">M,q,t,t,t,t,z</text>
+ <rect x="238" y="294" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="285" y="294" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="332" y="294" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="379" y="294" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="426" y="294" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="473" y="294" width="4" height="4" fill="#0000FF" stroke="none" />
+ <!-- ====================================================================== -->
+ <!-- Double Spade using M, q, Q, q, Q, & z ================================ -->
+ <!-- ====================================================================== -->
+ <path xml:id="Dbl_spd_MCcZ" fill="#0000C0" stroke="#00CF00" stroke-width="2" d="M172 193q-100 50 0 50Q72 243 172 293q100 -50 0 -50Q272 243 172 193z" />
+ <text font-size="12" x="48" y="280">M,q,Q,q,Q,z</text>
+ <rect x="170" y="191" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="170" y="241" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="170" y="291" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="170" y="241" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="170" y="191" width="4" height="4" fill="#FF0000" stroke="none" />
+ </g>
+ <g font-family="SVGFreeSansISO-8859-1,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.13 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansISO-8859-1,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-04-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-04-t.svg
new file mode 100644
index 0000000000..f084348ebc
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-04-t.svg
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN,AE" owner="LH" desc="Test that viewer has the basic capability to handle the &lt;path&gt; element and data (d) attribute in combination with the moveto, lineto, and closepath commands - M, L, Z, m, l, and z." status="accepted"
+ approved="yes"
+ version="$Revision: 1.12 $" testname="$RCSfile: paths-data-04-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verify the basic capability to handle the 'path' element, and its data attribute (d) in combination with the straight-line path commands. Two pairs of concentric equilateral triangles are drawn using respectively M,L,Z and m,l,z. The shapes are identical, with one stroked and one filled. The fill-mode default of "even-odd" means that the inner triangle is hollow.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-04-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Lines drawn with commands (absolute coordinates):</text>
+ <!-- ====================================================================== -->
+ <!-- First Group of Triangles using M, L & Z commands ===================== -->
+ <!-- ====================================================================== -->
+ <g transform="scale(1.8)">
+ <text font-size="12" x="125" y="30" text-anchor="middle">M,L,L,L,Z,</text>
+ <text font-size="12" x="125" y="46" text-anchor="middle">subpath</text>
+ <text font-size="12" x="125" y="61" text-anchor="middle">M,L,L,L,Z</text>
+ <path xml:id="Triangle_stroke_MLZ" fill="none" stroke="#000000" d=" M 62.00000 56.00000 L 113.96152 146.00000 L 10.03848 146.00000 L 62.00000 56.00000 Z M 62.00000 71.00000 L 100.97114 138.50000 L 23.02886 138.50000 L 62.00000 71.00000 Z " />
+ <rect x="60.00000" y="54.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="111.96152" y="144.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="8.03848" y="144.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="60.00000" y="69.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="98.97114" y="136.50000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="21.02886" y="136.50000" width="4" height="4" fill="#00C000" stroke="none" />
+ <text font-size="12" x="42" y="162">stroked</text>
+ <path xml:id="Triangle_fill_MLZ" fill="#FF0000" stroke="none" fill-rule="evenodd" d=" M 177.00000 56.00000 L 228.96152 146.00000 L 125.03848 146.00000 L 177.00000 56.00000 Z M 177.00000 71.00000 L 215.97114 138.50000 L 138.02886 138.50000 L 177.00000 71.00000 Z " />
+ <rect x="175.00000" y="54.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="226.96152" y="144.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="123.03848" y="144.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="175.00000" y="69.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="213.97114" y="136.50000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="136.02886" y="136.50000" width="4" height="4" fill="#00C000" stroke="none" />
+ <text font-size="12" x="162" y="162">filled</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.12 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-05-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-05-t.svg
new file mode 100644
index 0000000000..f22ba0d745
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-05-t.svg
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN,AE" owner="LH" desc="Test that viewer has the basic capability to handle the &lt;path&gt; element and data (d) attribute in combination with the moveto, lineto, and closepath commands - M, L, Z, m, l, and z." status="accepted"
+ approved="yes"
+ version="$Revision: 1.13 $" testname="$RCSfile: paths-data-05-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verify the basic capability to handle the 'path' element, and its data attribute (d) in combination with the straight-line path commands. Two pairs of concentric equilateral triangles are drawn using respectively M,L,Z and m,l,z. The shapes in each pair are identical, with one stroked and one filled. The fill-mode default of "even-odd" means that the inner triangle is hollow.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-05-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Lines drawn with commands (relative coordinates):</text>
+ <!-- ====================================================================== -->
+ <!-- Second Group of Triangles using m, l & z commands===================== -->
+ <!-- ====================================================================== -->
+ <g transform="scale(1.8) translate(0, -150)">
+ <text font-size="12" x="125" y="180" text-anchor="middle">m,l,l,l,z,</text>
+ <text font-size="12" x="125" y="194" text-anchor="middle">subpath</text>
+ <text font-size="12" x="125" y="208" text-anchor="middle">m,l,l,l,z</text>
+ <path xml:id="Triangle_stroke_mlz" fill="none" stroke="#000000" d=" m 62.00000 190.00000 l 51.96152 90.00000 l -103.92304 0.00000 l 51.96152 -90.00000 z m 0.00000 15.00000 l 38.97114 67.50000 l -77.91228 0.00000 l 38.97114 -67.50000 z " />
+ <rect x="60.00000" y="188.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="111.96152" y="278.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="8.03848" y="278.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="60.00000" y="203.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="98.97114" y="270.50000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="21.02886" y="270.50000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <path xml:id="Triangle_fill_mlz" fill="#00C000" stroke="none" fill-rule="evenodd" d=" m 177.00000 190.00000 l 51.96152 90.00000 l -103.92304 0.00000 l 51.96152 -90.00000 z m 0.00000 15.00000 l 38.97114 67.50000 l -77.91228 0.00000 l 38.97114 -67.50000 z " />
+ <rect x="175.00000" y="188.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="226.96152" y="278.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="123.03848" y="278.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="175.00000" y="203.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="213.97114" y="270.50000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="136.02886" y="270.50000" width="4" height="4" fill="#FF0000" stroke="none" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.13 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-06-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-06-t.svg
new file mode 100644
index 0000000000..a2863c221a
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-06-t.svg
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN,AE" owner="LH" desc="Test that viewer has the basic capability to handle the &lt;path&gt; element and data (d) attribute in combination with the moveto, lineto, and closepath commands - M, L, Z, m, l, and z." status="accepted"
+ approved="yes"
+ version="$Revision: 1.12 $" testname="$RCSfile: paths-data-06-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verify the basic capability to handle the 'path' element, and its data attribute (d) in combination with the straight-line path commands. Two pairs of staircase figures are drawn using respectively M,H,V,Z and m,h,v,z. The shapes in each pair are identical, with one stroked and one filled.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-06-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Horizontal and Vertical Lines drawn with commands (absolute coordinates):</text>
+ <g transform="scale(1.8) translate(-200, 0)">
+ <!-- ====================================================================== -->
+ <!-- First Group of Stairs using M, H, V & Z commands====================== -->
+ <!-- ====================================================================== -->
+ <text font-size="12" x="288" y="30">M,H,V,H,</text>
+ <text font-size="12" x="288" y="46">V,H,V,H,</text>
+ <text font-size="12" x="304" y="62">V,Z</text>
+ <path xml:id="Stairs_stroke_MHVZ" fill="none" stroke="#000000" d=" M 240.00000 56.00000 H 270.00000 V 86.00000 H 300.00000 V 116.00000 H 330.00000 V 146.00000 H 240.00000 V 56.00000 Z " />
+ <rect x="238.00000" y="54.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="268.00000" y="54.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="268.00000" y="84.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="298.00000" y="84.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="298.00000" y="114.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="328.00000" y="114.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="328.00000" y="144.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="238.00000" y="144.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <path xml:id="Stairs_fill_MHVZ" fill="#0000FF" stroke="none" d=" M 350.00000 56.00000 H 380.00000 V 86.00000 H 410.00000 V 116.00000 H 440.00000 V 146.00000 H 350.00000 V 56.00000 Z " />
+ <rect x="348.00000" y="54.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="378.00000" y="54.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="378.00000" y="84.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="408.00000" y="84.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="408.00000" y="114.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="438.00000" y="114.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="438.00000" y="144.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <rect x="348.00000" y="144.00000" width="4" height="4" fill="#FFFF00" stroke="none" />
+ <!-- ====================================================================== -->
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.12 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-07-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-07-t.svg
new file mode 100644
index 0000000000..6449e60f76
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-07-t.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN,AE" owner="LH" desc="Test that viewer has the basic capability to handle the &lt;path&gt; element and data (d) attribute in combination with the moveto, lineto, and closepath commands - M, L, Z, m, l, and z." status="accepted"
+ approved="yes"
+ version="$Revision: 1.12 $" testname="$RCSfile: paths-data-07-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verify the basic capability to handle the 'path' element, and its data attribute (d) in combination with the straight-line path commands. Two pairs of staircase figures are drawn using respectively M,H,V,Z and m,h,v,z. The shapes in each pair are identical, with one stroked and one filled.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-07-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Horizontal and Vertical Lines drawn with commands (relative coordinates):</text>
+ <g transform="scale(1.8) translate(-200, -150)">
+ <!-- ====================================================================== -->
+ <!-- Second Group of Stairs using m, h, v & z commands====================== -->
+ <!-- ====================================================================== -->
+ <text font-size="12" x="288" y="180">m,h,v,h</text>
+ <text font-size="12" x="288" y="194">v,h,v,h</text>
+ <text font-size="12" x="304" y="208">v,z</text>
+ <path xml:id="Stairs_stroke_mhvz" fill="none" stroke="#000000" d=" m 240.00000 190.00000 h 30.00000 v 30.00000 h 30.00000 v 30.00000 h 30.00000 v 30.00000 h -90.00000 v -90.00000 z " />
+ <rect x="238.00000" y="188.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="268.00000" y="188.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="268.00000" y="218.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="298.00000" y="218.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="298.00000" y="248.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="328.00000" y="248.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="328.00000" y="278.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="238.00000" y="278.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <path xml:id="Stairs_fill_mhvz" fill="#FFFF00" stroke="none" d=" m 350.00000 190.00000 h 30.00000 v 30.00000 h 30.00000 v 30.00000 h 30.00000 v 30.00000 h -90.00000 v -90.00000 z " />
+ <rect x="348.00000" y="188.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="378.00000" y="188.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="378.00000" y="218.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="408.00000" y="218.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="408.00000" y="248.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="438.00000" y="248.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="438.00000" y="278.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ <rect x="348.00000" y="278.00000" width="4" height="4" fill="#0000FF" stroke="none" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.12 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-08-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-08-t.svg
new file mode 100644
index 0000000000..ff358eaf46
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-08-t.svg
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN,AN" owner="SH" desc="tests support for moveto and closepath path commands" status="accepted"
+ approved="yes"
+ version="$Revision: 1.9 $" testname="$RCSfile: paths-data-08-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verify the basic capability to handle the 'path' element, and its data attribute (d) in combination with the straight-line path commands. Two pairs of concentric equilateral triangles are drawn using M and Z. No L commands are used in this test as they are implied after an M or Z command. The shapes are identical, with one stroked and one filled. The fill-mode default of "even-odd" means that the inner triangle is hollow.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-08-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- ====================================================================== -->
+ <!-- First Group of Triangles using M & Z commands ======================== -->
+ <!-- ====================================================================== -->
+ <text font-size="12" x="240" y="14" text-anchor="middle">Lines drawn with commands (testing implicit followup of 'L' commands):</text>
+ <text font-size="24" x="180" y="64">M and Z</text>
+ <g transform="scale(1.8)">
+ <path xml:id="Triangle_stroke_MZ" fill="none" stroke="#000000" d=" M 62.00000 56.00000 113.96152 146.00000 10.03848 146.00000 62.00000 56.00000 Z M 62.00000 71.00000 100.97114 138.50000 23.02886 138.50000 62.00000 71.00000 Z " />
+ <rect x="60.00000" y="54.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="111.96152" y="144.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="8.03848" y="144.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="60.00000" y="69.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="98.97114" y="136.50000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="21.02886" y="136.50000" width="4" height="4" fill="#00C000" stroke="none" />
+ <text font-size="12" x="42" y="162">stroked</text>
+ <path xml:id="Triangle_fill_MZ" fill="#FF0000" stroke="none" fill-rule="evenodd" d=" M 177.00000 56.00000 228.96152 146.00000 125.03848 146.00000 177.00000 56.00000 Z M 177.00000 71.00000 215.97114 138.50000 138.02886 138.50000 177.00000 71.00000 Z " />
+ <rect x="175.00000" y="54.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="226.96152" y="144.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="123.03848" y="144.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="175.00000" y="69.00000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="213.97114" y="136.50000" width="4" height="4" fill="#00C000" stroke="none" />
+ <rect x="136.02886" y="136.50000" width="4" height="4" fill="#00C000" stroke="none" />
+ <text font-size="12" x="162" y="162">filled</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-09-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-09-t.svg
new file mode 100644
index 0000000000..c3824cef24
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-09-t.svg
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN,AN" owner="SH" desc="tests moveto and closepath path commands" status="accepted"
+ approved="yes"
+ version="$Revision: 1.9 $" testname="$RCSfile: paths-data-09-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verify the basic capability to handle the 'path' element, and its data attribute (d) in combination with the straight-line path commands. Two pairs of concentric equilateral triangles are drawn using m and z. No l commands are used in this test as they are implied after an m or z command. The shapes are identical, with one stroked and one filled. The fill-mode default of "even-odd" means that the inner triangle is hollow.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-09-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- ====================================================================== -->
+ <!-- Second Group of Triangles using m & z commands ===================== -->
+ <!-- ====================================================================== -->
+ <text font-size="12" x="240" y="14" text-anchor="middle">Lines drawn with commands (testing implicit followup of 'l' commands):</text>
+ <text font-size="24" x="180" y="64">m and z</text>
+ <g transform="scale(1.8) translate(0, -150)">
+ <path xml:id="Triangle_stroke_mz" fill="none" stroke="#000000" d=" m 62.00000 190.00000 51.96152 90.00000 -103.92304 0.00000 51.96152 -90.00000 z m 0.00000 15.00000 38.97114 67.50000 -77.91228 0.00000 38.97114 -67.50000 z " />
+ <rect x="60.00000" y="188.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="111.96152" y="278.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="8.03848" y="278.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="60.00000" y="203.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="98.97114" y="270.50000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="21.02886" y="270.50000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <path xml:id="Triangle_fill_mz" fill="#00C000" stroke="none" fill-rule="evenodd" d=" m 177.00000 190.00000 51.96152 90.00000 -103.92304 0.00000 51.96152 -90.00000 z m 0.00000 15.00000 38.97114 67.50000 -77.91228 0.00000 38.97114 -67.50000 z " />
+ <rect x="175.00000" y="188.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="226.96152" y="278.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="123.03848" y="278.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="175.00000" y="203.00000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="213.97114" y="270.50000" width="4" height="4" fill="#FF0000" stroke="none" />
+ <rect x="136.02886" y="270.50000" width="4" height="4" fill="#FF0000" stroke="none" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-10-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-10-t.svg
new file mode 100644
index 0000000000..03231dfc71
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-10-t.svg
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN,AN" owner="SH" desc="tests paths with closepath vs. same start and end point" status="accepted"
+ approved="yes"
+ version="$Revision: 1.11 $" testname="$RCSfile: paths-data-10-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verify that the viewer renders the line caps and line joins for open and closed paths properly. Verify that the open triangular paths are stroked differently at ends of the path than they are at their intermediate corners. In contrast, the corners of a closed path should all appear the same.</p>
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-10-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing correct stroking with open and closed paths</text>
+ <g transform="scale(0.9),translate(20,30)">
+ <g transform="translate(10,10)">
+ <text font-size="18" x="10" y="20">open</text>
+ <text font-size="18" x="10" y="38">join=round</text>
+ <text font-size="18" x="10" y="56">cap=butt</text>
+ <text font-size="18" x="10" y="74">M,L</text>
+ <g transform="translate(115,0)">
+ <path xml:id="triangle-01" fill="green" stroke="red" stroke-width="15" stroke-linecap="butt" stroke-linejoin="round" d="M 100 0 L 100 80 0 40 100 0" />
+ </g>
+ </g>
+ <g transform="translate(10,115)">
+ <text font-size="18" x="10" y="20">open</text>
+ <text font-size="18" x="10" y="38">join=bevel</text>
+ <text font-size="18" x="10" y="56">cap=round</text>
+ <text font-size="18" x="10" y="74">m,l</text>
+ <g transform="translate(115,0)">
+ <path xml:id="triangle-02" fill="green" stroke="red" stroke-width="15" stroke-linecap="round" stroke-linejoin="bevel" d="m 100 0 l 0 80 -100 -40 100 -40" />
+ </g>
+ </g>
+ <g transform="translate(10,220)">
+ <text font-size="18" x="10" y="20">open</text>
+ <text font-size="18" x="10" y="38">join=miter</text>
+ <text font-size="18" x="10" y="56">cap=square</text>
+ <text font-size="18" x="10" y="74">M,L</text>
+ <g transform="translate(115,0)">
+ <path xml:id="triangle-03" fill="green" stroke="red" stroke-width="15" stroke-linecap="square" stroke-linejoin="miter" d="M 100 0 L 100 80 0 40 100 0" />
+ </g>
+ </g>
+ <g transform="translate(250,10)">
+ <text font-size="18" x="125" y="20">closed</text>
+ <text font-size="18" x="125" y="38">join=round</text>
+ <text font-size="18" x="125" y="56">cap=butt</text>
+ <text font-size="18" x="125" y="74">M,L,Z</text>
+ <g transform="translate(0,0)">
+ <path xml:id="triangle-04" fill="green" stroke="red" stroke-width="15" stroke-linecap="butt" stroke-linejoin="round" d="M 0 0 L 100 40 0 80 Z" />
+ </g>
+ </g>
+ <g transform="translate(250,115)">
+ <text font-size="18" x="125" y="20">closed</text>
+ <text font-size="18" x="125" y="38">join=bevel</text>
+ <text font-size="18" x="125" y="56">cap=round</text>
+ <text font-size="18" x="125" y="74">m,l,z</text>
+ <g transform="translate(0,0)">
+ <path xml:id="triangle-05" fill="green" stroke="red" stroke-width="15" stroke-linecap="round" stroke-linejoin="bevel" d="m 0 0 l 100 40 -100 40 z" />
+ </g>
+ </g>
+ <g transform="translate(250,220)">
+ <text font-size="18" x="125" y="20">closed</text>
+ <text font-size="18" x="125" y="38">join=miter</text>
+ <text font-size="18" x="125" y="56">cap=square</text>
+ <text font-size="18" x="125" y="74">M,L,Z</text>
+ <g transform="translate(0,0)">
+ <path xml:id="triangle-06" fill="green" stroke="red" stroke-width="15" stroke-linecap="square" stroke-linejoin="miter" d="M 0 0 L 100 40 0 80 Z" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.11 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-12-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-12-t.svg
new file mode 100644
index 0000000000..1357183abc
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-12-t.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED,AN" owner="CN" desc="Test using multiple coord sets to build a polybézier, and implicit values for initial S." status="accepted"
+ approved="yes"
+ version="$Revision: 1.11 $" testname="$RCSfile: paths-data-12-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test using multiple coord sets to build a polybézier, and implicit values for initial S.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-12-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansISO-8859-1" unicode-range="U+0-FF">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans-ISO-8859-1.svg#iso_8859_1" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansISO-8859-1,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing cubic bézier curves and implicit values for 'S':</text>
+ <text font-size="24" x="220" y="64">M,C,S</text>
+ <text font-size="24" x="220" y="250">M,S</text>
+ <!-- Use multiple coord sets to build a polybézier-->
+ <path fill="none" stroke="red" stroke-width="3" d="M 100 100 C 100 20 200 20 200 100 S 300 180 300 100" />
+ <rect x="100" y="100" width="4" height="4" fill="blue" stroke="none" />
+ <rect x="200" y="100" width="4" height="4" fill="blue" stroke="none" />
+ <rect x="300" y="100" width="4" height="4" fill="blue" stroke="none" />
+ <!-- Test if S not preceeded by either C or S , first control point is coincident with the current point.-->
+ <path fill="none" stroke="red" stroke-width="3" d="M 100 250 S 200 200 200 250 300 300 300 250" />
+ <rect x="100" y="250" width="4" height="4" fill="blue" stroke="none" />
+ <rect x="200" y="200" width="4" height="4" fill="blue" stroke="none" />
+ <rect x="200" y="250" width="4" height="4" fill="blue" stroke="none" />
+ <rect x="200" y="300" width="4" height="4" fill="blue" stroke="none" />
+ <rect x="300" y="300" width="4" height="4" fill="blue" stroke="none" />
+ <rect x="300" y="250" width="4" height="4" fill="blue" stroke="none" />
+ </g>
+ <g font-family="SVGFreeSansISO-8859-1,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.11 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansISO-8859-1,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-13-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-13-t.svg
new file mode 100644
index 0000000000..32abd1462b
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-13-t.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED,AN" owner="CN" desc="Test multiple coridinates for V and H" status="accepted"
+ approved="yes"
+ version="$Revision: 1.10 $" testname="$RCSfile: paths-data-13-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test multiple coordinates for V and H. There should be one horizontal red line and one vertical blue line.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-13-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing implicit followup of 'V' and 'H' commands):</text>
+ <text font-size="24" x="180" y="64">M,H</text>
+ <text font-size="24" x="260" y="230">M,V</text>
+ <!-- Use multiple coords to H, should get a straight horizontal line -->
+ <path stroke="red" stroke-width="5" d=" M 240.00000 56.00000 H 270.00000 300.00000 320.00000 400.00000 " />
+ <!-- Use multiple coords to V, should get a straight vertical line -->
+ <path stroke="blue" stroke-width="5" d=" M 240.00000 156.00000 V 180.00000 200.00000 260.00000 300.00000 " />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-14-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-14-t.svg
new file mode 100644
index 0000000000..c2f852ecd4
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-14-t.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED,AN" owner="CN" desc="Test implicit values for moveto." status="accepted"
+ approved="yes"
+ version="$Revision: 1.10 $" testname="$RCSfile: paths-data-14-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test implicit values for moveto. If the first command is 'm' it should be taken as an absolute moveto, plus implicit lineto.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-14-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing implicit followup of 'l/L' commands succeeding 'm/M', commands:</text>
+ <text font-size="24" x="110" y="75" text-anchor="middle">m,z,m,z</text>
+ <text font-size="24" x="315" y="75" text-anchor="middle">M,Z,M,Z</text>
+ <g transform="scale(1.8)">
+ <!-- If the first command is 'm' it should be taken as an absolute moveto, plus implicit lineto. -->
+ <path fill="none" stroke="#000000" d=" m 62.00000 56.00000 51.96152 90.00000 -103.92304 0.00000 51.96152 -90.00000 z m 0.00000 15.00000 38.97114 67.50000 -77.91228 0.00000 38.97114 -67.50000 z " />
+ <!-- Test implicit lineto. -->
+ <path fill="#FF0000" stroke="none" fill-rule="evenodd" d=" M 177.00000 56.00000 228.96152 146.00000 125.03848 146.00000 177.00000 56.00000 Z M 177.00000 71.00000 215.97114 138.50000 138.02886 138.50000 177.00000 71.00000 Z " />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-15-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-15-t.svg
new file mode 100644
index 0000000000..c685e0bd36
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/paths-data-15-t.svg
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN,ED" owner="CN" desc="Test using multiple coord sets to build a polybézier, then T with no preceeding Q or T." status="accepted"
+ approved="yes"
+ version="$Revision: 1.10 $" testname="$RCSfile: paths-data-15-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test using multiple coord sets to build a polybézier, then T with no preceding Q or T.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labeling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: paths-data-15-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansISO-8859-1" unicode-range="U+0-FF">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans-ISO-8859-1.svg#iso_8859_1" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansISO-8859-1,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing implement followup of commands for quadratic bézier curves</text>
+ <text font-size="24" x="210" y="120">M,Q</text>
+ <text font-size="24" x="200" y="190">M,T</text>
+ <g transform="scale(1.8) translate(20 50)">
+ <!-- Use multiple coord sets to build a polybezier-->
+ <path fill="none" stroke="red" stroke-width="3" d="M 20 20 Q 50 10 80 20 110 30 140 20 170 10 200 20" />
+ <!-- Test if T not preceded by either Q or T , control point should be coincident with the current point.-->
+ <path fill="none" stroke="blue" stroke-width="3" d="M 20 50 T 50 50 80 50" />
+ <rect x="20" y="50" width="4" height="4" fill="#0000FF" stroke="black" />
+ <rect x="50" y="50" width="4" height="4" fill="#0000FF" stroke="black" />
+ <rect x="80" y="50" width="4" height="4" fill="#0000FF" stroke="black" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansISO-8859-1,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansISO-8859-1,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g> -->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-01-t.svg
new file mode 100644
index 0000000000..5a280242c1
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-01-t.svg
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="VH" desc="This test validates that shapes can be both filled." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: render-elems-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verifies that shapes can be filled.</p>
+ <p>There is one pair of octagons. These are filled.</p>
+ <p>The rendered image should match the reference image except for the text which may show minor layout differences.</p>
+ <p>The test uses the 'path' element, as well as basic fill (solid primary colors), stroke (primary color 1-pixel and wide lines), font-family (Arial) and font-size properties - the common prerequisites.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: render-elems-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- ====================================================================== -->
+ <!-- First, fill shape with two different colors -->
+ <!-- ====================================================================== -->
+ <g transform="translate(30, 80)">
+ <g fill="red">
+ <path d="M60,0 l60,0 l60,60 l0,60 l-60,60 l-60,0 l-60,-60 l0,-60 z" />
+ </g>
+ <g fill="black" transform="translate(200, 0)">
+ <path d="M60,0 l60,0 l60,60 l0,60 l-60,60 l-60,0 l-60,-60 l0,-60 z" />
+ </g>
+ <text x="130" y="-30" font-size="28">Shape fill</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-02-t.svg
new file mode 100644
index 0000000000..8c4c6accc4
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-02-t.svg
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg [
+ <!ENTITY shape "<path d='M60,0 l60,0 l60,60 l0,60 l-60,60 l-60,0 l-60,-60 l0,-60 z' />">
+]>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="VH" desc="This test validates that shapes can be both stroked." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: render-elems-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verifies that shapes can be stroked.</p>
+ <p>There is one pair of octagons. These are stroked.</p>
+ <p>The rendered image should match the reference image except for the text which may show minor layout differences.</p>
+ <p>The test uses the 'rect' element, as well as basic fill (solid primary colors), stroke (primary color 1-pixel and wide lines), font-family (Arial) and font-size properties - the common prerequisites.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: render-elems-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- ====================================================================== -->
+ <!-- Now, stroke shape with two different stroke width and color -->
+ <!-- ====================================================================== -->
+ <g transform="translate(30, 80)">
+ <g fill="none" stroke="red" stroke-width="3">
+ <path d="M60,0 l60,0 l60,60 l0,60 l-60,60 l-60,0 l-60,-60 l0,-60 z" />
+ </g>
+ <g fill="none" stroke="black" stroke-width="9" transform="translate(200, 0)">
+ <path d="M60,0 l60,0 l60,60 l0,60 l-60,60 l-60,0 l-60,-60 l0,-60 z" />
+ </g>
+ <text x="110" y="-30" font-size="28">Shape stroke</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-03-t.svg
new file mode 100644
index 0000000000..4900b63850
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-03-t.svg
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg [
+ <!ENTITY shape "<path d='M60,0 l60,0 l60,60 l0,60 l-60,60 l-60,0 l-60,-60 l0,-60 z' />">
+]>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="VH" desc="This test validates that shapes can be both filled and stroked." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: render-elems-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verifies that shapes can be filled, stroked and the order of filling and stroking.</p>
+ <p>There is one pair of octagons. These are filled plus stroked.</p>
+ <p>The rendered image should match the reference image except for the text which may show minor layout differences.</p>
+ <p>The test uses the 'rect' element, as well as basic fill (solid primary colors), stroke (primary color 1-pixel and wide lines), font-family (Arial) and font-size properties - the common prerequisites.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: render-elems-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <!-- ====================================================================== -->
+ <!-- Now, fill and stroke. The fill should happen first -->
+ <!-- ====================================================================== -->
+ <g transform="translate(30, 80)">
+ <g fill="yellow" stroke="red" stroke-width="8">&shape;</g>
+ <g stroke="black" fill="blue" stroke-width="8" transform="translate(200, 0)">&shape;</g>
+ <text x="70" y="-30" font-size="28">Shape fill and stroke</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-06-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-06-t.svg
new file mode 100644
index 0000000000..64c5863c41
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-06-t.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="VH" desc="This test validates that text can be both filled." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: render-elems-06-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verifies that text can be filled. The test shows two 'A' characters that are filled and not stroked.</p>
+ <p>The rendered image should match the reference image except for the text which may show minor layout differences.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: render-elems-06-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font xml:id="MyFont" horiz-adv-x="416">
+ <font-face font-family="MyFont" units-per-em="1000" panose-1="2 0 0 6 3 0 0 2 0 4" ascent="700" descent="-127" />
+ <missing-glyph horiz-adv-x="500" />
+ <glyph unicode="A" glyph-name="A" horiz-adv-x="505" d="M73 700L5 0H155L170 165H335L350 0H500L432 700H73ZM183 315L205 550H300L322 315H183Z" />
+ <glyph unicode="B" glyph-name="B" horiz-adv-x="550" d="M40 700V0H510V280L423 350L510 420V700H40ZM360 550V471L306 420H190V550H360ZM190 280H306L360 229V150H190V280Z" />
+ </font>
+ </defs>
+ <!-- ====================================================================== -->
+ <!-- First, fill text with two different colors -->
+ <!-- ====================================================================== -->
+ <text x="180" y="40" font-size="30">Text fill</text>
+ <g font-size="300" font-family="MyFont">
+ <text x="60" y="280" fill="red">A</text>
+ <text x="260" y="280" fill="navy">A</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-07-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-07-t.svg
new file mode 100644
index 0000000000..db9a64f40f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-07-t.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="VH" desc="This test validates that text can be both stroked." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: render-elems-07-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verifies that text can be stroked. The The test shows two characters that are stroked and not filled.</p>
+ <p>The rendered image should match the reference image except for the text which may show minor layout differences.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: render-elems-07-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font xml:id="MyFont" horiz-adv-x="416">
+ <font-face font-family="MyFont" units-per-em="1000" panose-1="2 0 0 6 3 0 0 2 0 4" ascent="700" descent="-127" />
+ <missing-glyph horiz-adv-x="500" />
+ <glyph unicode="A" glyph-name="A" horiz-adv-x="505" d="M73 700L5 0H155L170 165H335L350 0H500L432 700H73ZM183 315L205 550H300L322 315H183Z" />
+ <glyph unicode="B" glyph-name="B" horiz-adv-x="550" d="M40 700V0H510V280L423 350L510 420V700H40ZM360 550V471L306 420H190V550H360ZM190 280H306L360 229V150H190V280Z" />
+ </font>
+ </defs>
+ <!-- ====================================================================== -->
+ <!-- Now, stroke text with two different stroke width and color -->
+ <!-- ====================================================================== -->
+ <text x="180" y="40" font-size="30">Text stroke</text>
+ <g font-size="300" font-family="MyFont">
+ <text x="60" y="280" fill="none" stroke="red" stroke-width="12">A</text>
+ <text x="260" y="280" fill="none" stroke="navy" stroke-width="12">B</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-08-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-08-t.svg
new file mode 100644
index 0000000000..bda095fef1
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-elems-08-t.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="VH" desc="This test validates that text can be both filled and stroked." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: render-elems-08-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verifies that text can be stroked. The test shows two 'A' characters that are both stroked and filled.</p>
+ <p>The rendered image should match the reference image except for the text which may show minor layout differences.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: render-elems-08-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font xml:id="MyFont" horiz-adv-x="416">
+ <font-face font-family="MyFont" units-per-em="1000" panose-1="2 0 0 6 3 0 0 2 0 4" ascent="700" descent="-127" />
+ <missing-glyph horiz-adv-x="500" />
+ <glyph unicode="A" glyph-name="A" horiz-adv-x="505" d="M73 700L5 0H155L170 165H335L350 0H500L432 700H73ZM183 315L205 550H300L322 315H183Z" />
+ <glyph unicode="B" glyph-name="B" horiz-adv-x="550" d="M40 700V0H510V280L423 350L510 420V700H40ZM360 550V471L306 420H190V550H360ZM190 280H306L360 229V150H190V280Z" />
+ </font>
+ </defs>
+ <!-- ====================================================================== -->
+ <!-- Now, fill and stroke. The fill should happen first -->
+ <!-- ====================================================================== -->
+ <text x="120" y="40" font-size="30">Text fill and stroke</text>
+ <g font-size="300" font-family="MyFont">
+ <text x="60" y="280" fill="#f82" stroke="red" stroke-width="12">A</text>
+ <text x="260" y="280" fill="#9ae" stroke="navy" stroke-width="12">B</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-groups-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-groups-01-t.svg
new file mode 100644
index 0000000000..5e49fe2b28
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-groups-01-t.svg
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR, DS" owner="VH, AS" desc="This test validates the rendering order of graphic elements and the concept of grouping." status="accepted"
+ approved="yes"
+ version="$Revision: 1.9 $" testname="$RCSfile: render-groups-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verifies implicit rendering order (paragraph 3.3) and grouping mechanism (paragraphs 3.4). It also validates basic Shape, Image and text rendering.</p>
+ <p>This test renders 3 elements: a text string "SVG", then a shape, then an image. Because of their definition order and coordinates, the image should be on top of the rectangle and the rectangle on top of the text. None of the "SVG" should show through the rectangle and none of the rectangle should show through the image.</p>
+ <p>Prerequisites: the test assumes proper handling of the fill stroke, stroke-width, font-size rendering properties. It uses the rect, line, text and image elements, as well as all the elements required for the test template. To ensure that the text string is overlapped by the other elements and to avoid a dependency on system fonts, an SVG font is used.</p>
+ <p>The rendered image should match the reference image exactly.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: render-groups-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font horiz-adv-x="313">
+ <!-- Converted from Larabie Anglepoise by Batik ttf2svg -->
+ <font-face font-family="larabie-anglepoise" units-per-em="1000" panose-1="0 0 4 0 0 0 0 0 0 0" ascent="703" descent="-300" alphabetic="0" />
+ <missing-glyph horiz-adv-x="500" d="M63 0V700H438V0H63ZM125 63H375V638H125V63Z" />
+ <glyph unicode="S" glyph-name="S" horiz-adv-x="385" d="M371 1H29V144H264Q264 151 264 166Q265 180 265 188Q265 212 249 212H132Q83 212 55 247Q29 279 29 329V566H335V422H136V375Q136 360 144 356Q148 355 168 355H279Q327 355 352 309Q371 273 371 221V1Z" />
+ <glyph unicode="V" glyph-name="V" horiz-adv-x="351" d="M365 563L183 -33L0 563H101L183 296L270 563H365Z" />
+ <glyph unicode="G" glyph-name="G" horiz-adv-x="367" d="M355 1H18V564H355V420H125V144H248V211H156V355H355V1Z" />
+ <hkern g1="V" g2="G" k="-40" />
+ </font>
+ </defs>
+ <!-- ====================================================================== -->
+ <!-- 3 overlapping elements in a group -->
+ <!-- ====================================================================== -->
+ <g transform="scale(1.8, 1.8)">
+ <!-- Background pattern -->
+ <rect x="20" y="10" width="230" height="155" fill="rgb(192, 192, 192)" />
+ <line x1="40" y1="10" x2="40" y2="175" stroke="white" stroke-width="15" />
+ <line x1="70" y1="10" x2="70" y2="175" stroke="white" stroke-width="15" />
+ <line x1="100" y1="10" x2="100" y2="175" stroke="white" stroke-width="15" />
+ <line x1="130" y1="10" x2="130" y2="175" stroke="white" stroke-width="15" />
+ <line x1="160" y1="10" x2="160" y2="175" stroke="white" stroke-width="15" />
+ <line x1="190" y1="10" x2="190" y2="175" stroke="white" stroke-width="15" />
+ <line x1="220" y1="10" x2="220" y2="175" stroke="white" stroke-width="15" />
+ <line x1="250" y1="10" x2="250" y2="175" stroke="white" stroke-width="15" />
+ <rect x="20" y="10" width="230" height="155" fill="none" stroke="black" />
+ <g >
+ <text font-family="larabie-anglepoise" font-size="120" x="30" y="90">SVG</text>
+ <rect x="70" y="55" width="130" height="70" fill="rgb(130, 0, 50)" />
+ <image x="162" y="75" width="80" height="80" xlink:href="../images/sign.png" />
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-groups-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-groups-03-t.svg
new file mode 100644
index 0000000000..26e54f4b04
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/render-groups-03-t.svg
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="NR" owner="VH" desc="This test validates the rendering order of graphic elements." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: render-groups-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verifies implicit rendering order (paragraph 3.3) and grouping mechanism (paragraphs 3.4). It also validates basic Shape, Image and text rendering.</p>
+ <p>This test renders 3 elements: a text string "SVG", then a shape, then an image. Because of their definition order and coordinates, the image should be on top of the rectangle and the rectangle on top of the text. None of the "SVG" should show through the rectangle and none of the rectangle should show through the image.</p>
+ <p>Prerequisites: the test assumes proper handling of the fill stroke, stroke-width, font-size rendering properties. It uses the rect, line, text and image elements, as well as all the elements required for the test template. To ensure that the text string is overlapped by the other elements and to avoid a dependency on system fonts, an SVG font is used.</p>
+ <p>The rendered image should match the reference image exactly.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: render-groups-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font horiz-adv-x="313">
+ <!-- Converted from Larabie Anglepoise by Batik ttf2svg -->
+ <font-face font-family="larabie-anglepoise" units-per-em="1000" panose-1="0 0 4 0 0 0 0 0 0 0" ascent="703" descent="-300" alphabetic="0" />
+ <missing-glyph horiz-adv-x="500" d="M63 0V700H438V0H63ZM125 63H375V638H125V63Z" />
+ <glyph unicode="S" glyph-name="S" horiz-adv-x="385" d="M371 1H29V144H264Q264 151 264 166Q265 180 265 188Q265 212 249 212H132Q83 212 55 247Q29 279 29 329V566H335V422H136V375Q136 360 144 356Q148 355 168 355H279Q327 355 352 309Q371 273 371 221V1Z" />
+ <glyph unicode="V" glyph-name="V" horiz-adv-x="351" d="M365 563L183 -33L0 563H101L183 296L270 563H365Z" />
+ <glyph unicode="G" glyph-name="G" horiz-adv-x="367" d="M355 1H18V564H355V420H125V144H248V211H156V355H355V1Z" />
+ <hkern g1="V" g2="G" k="-40" />
+ </font>
+ </defs>
+ <!-- ====================================================================== -->
+ <!-- 3 overlapping elements in a group with opacity -->
+ <!-- ====================================================================== -->
+ <g transform="scale(1.8, 1.8)">
+ <!-- Background pattern -->
+ <rect x="20" y="10" width="230" height="155" fill="rgb(192, 192, 192)" />
+ <line x1="40" y1="10" x2="40" y2="175" stroke="white" stroke-width="15" />
+ <line x1="70" y1="10" x2="70" y2="175" stroke="white" stroke-width="15" />
+ <line x1="100" y1="10" x2="100" y2="175" stroke="white" stroke-width="15" />
+ <line x1="130" y1="10" x2="130" y2="175" stroke="white" stroke-width="15" />
+ <line x1="160" y1="10" x2="160" y2="175" stroke="white" stroke-width="15" />
+ <line x1="190" y1="10" x2="190" y2="175" stroke="white" stroke-width="15" />
+ <line x1="220" y1="10" x2="220" y2="175" stroke="white" stroke-width="15" />
+ <line x1="250" y1="10" x2="250" y2="175" stroke="white" stroke-width="15" />
+ <rect x="20" y="10" width="230" height="155" fill="none" stroke="black" />
+ <!-- The following text, rectangle and image are drawn, fully opaque, in -->
+ <!-- the order they are defined. Therefore, none of the 'A' under the -->
+ <!-- rectangle should show. Neither should any of the rectangle under -->
+ <!-- the image. -->
+ <text font-family="larabie-anglepoise" font-size="120" x="30" y="90">SVG</text>
+ <rect x="70" y="55" width="130" height="70" fill="rgb(130, 0, 50)" />
+ <image x="162" y="75" width="80" height="80" xlink:href="../images/sign.png" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-circle-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-circle-01-t.svg
new file mode 100644
index 0000000000..ade3b09dca
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-circle-01-t.svg
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="LH" desc="Test ability to handle the 'circle' basic shapes element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.10 $" testname="$RCSfile: shapes-circle-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-circle-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the &lt;circle/&gt; element with different fill, stroke and stroke-width attributes</text>
+ <circle cx="100" cy="100" r="50" fill="none" stroke="black" />
+ <circle cx="220" cy="100" r="35" fill="red" stroke="black" />
+ <circle cx="340" cy="100" r="20" fill="black" stroke="lime" stroke-width="4" />
+ <circle cx="100" cy="260" r="20" stroke="lime" fill="yellow" stroke-width="4" />
+ <circle cx="220" cy="260" r="35" stroke="none" fill="blue" />
+ <circle cx="340" cy="260" r="50" stroke="red" fill="none" stroke-width="10" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-circle-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-circle-02-t.svg
new file mode 100644
index 0000000000..921ba47929
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-circle-02-t.svg
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="DJ,AN" owner="CN" desc="Defaults test with circle." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: shapes-circle-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Defaults test with circle.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-circle-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the default attributes on the &lt;circle/&gt; element</text>
+ <g fill="red" stroke="#000000" fill-opacity="0.5">
+ <!-- Set cx and cy coordinate to default.-->
+ <circle r="50" />
+ <!-- Set cx coordinate to default.-->
+ <circle cy="100" r="50" />
+ <!-- Set cy coordinate to default.-->
+ <circle cx="100" r="50" />
+ <!-- Set r attribute to 0 (should not display a circle).-->
+ <circle cx="100" cy="100" r="0" />
+ <!-- Set all values to draw a circle -->
+ <circle cx="100" cy="100" r="50" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-circle-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-circle-03-t.svg
new file mode 100644
index 0000000000..c421882089
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-circle-03-t.svg
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="AN" desc="Testing the correct stroking of the circle element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: shapes-circle-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Defaults test with circle.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-circle-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the correct stroking of the &lt;circle /&gt; element.</text>
+ <text font-size="12" x="160" y="106">3 'o clock starting point</text>
+ <text font-size="12" x="160" y="256">3 'o clock starting point</text>
+ <g fill="red" stroke="#000000">
+ <!-- upper left circle -->
+ <circle cx="100" cy="100" r="50" stroke-width="5" stroke-dasharray="50,5"/>
+ <!-- reference lines upper left circle -->
+ <line x1="100" y1="100" x2="127" y2="142.1" stroke-width="0.5" stroke="blue"/>
+ <line x1="100" y1="100" x2="122.7" y2="144.6" stroke-width="0.5" stroke="blue" />
+ <line x1="100" y1="100" x2="74.75" y2="143.2" stroke-width="0.5" stroke="blue"/>
+ <line x1="100" y1="100" x2="70.6" y2="140.4" stroke-width="0.5" stroke="blue" />
+ <line x1="100" y1="100" x2="50.1" y2="97.1" stroke-width="0.5" stroke="blue"/>
+ <line x1="100" y1="100" x2="50.6" y2="92.2" stroke-width="0.5" stroke="blue" />
+ <line x1="100" y1="100" x2="79.95" y2="54.42" stroke-width="0.5" stroke="blue"/>
+ <line x1="100" y1="100" x2="84.62" y2="52.45" stroke-width="0.5" stroke="blue" />
+ <line x1="100" y1="100" x2="131.72" y2="61.36" stroke-width="0.5" stroke="blue"/>
+ <line x1="100" y1="100" x2="135.4" y2="64.72" stroke-width="0.5" stroke="blue" />
+ <!-- line indicating the 3 'o clock starting point of upper left circle -->
+ <line x1="100" y1="100" x2="150" y2="100" stroke-width="2" stroke="blue"/>
+ <!-- lower left circle -->
+ <circle cx="100" cy="250" r="50" stroke-width="10" stroke-dasharray="305,15"/>
+ <!-- reference line lower left circle -->
+ <line x1="100" y1="250" x2="149.17" y2="240.88" stroke-width="0.5" stroke="blue"/>
+ <!-- line indicating the 3 'o clock starting point of lower left circle -->
+ <line x1="100" y1="250" x2="150" y2="250" stroke-width="2" stroke="blue" />
+ <!-- upper right circle -->
+ <circle cx="400" cy="100" r="50" stroke-width="5" stroke-dasharray="50,5" stroke-linecap="round"/>
+ <!-- reference lines upper right circle -->
+ <line x1="400" y1="100" x2="427" y2="142.1" stroke-width="0.5" stroke="blue"/>
+ <line x1="400" y1="100" x2="422.7" y2="144.6" stroke-width="0.5" stroke="blue" />
+ <line x1="400" y1="100" x2="374.75" y2="143.2" stroke-width="0.5" stroke="blue"/>
+ <line x1="400" y1="100" x2="370.6" y2="140.4" stroke-width="0.5" stroke="blue" />
+ <line x1="400" y1="100" x2="350.1" y2="97.1" stroke-width="0.5" stroke="blue"/>
+ <line x1="400" y1="100" x2="350.6" y2="92.2" stroke-width="0.5" stroke="blue" />
+ <line x1="400" y1="100" x2="379.95" y2="54.42" stroke-width="0.5" stroke="blue"/>
+ <line x1="400" y1="100" x2="384.62" y2="52.45" stroke-width="0.5" stroke="blue" />
+ <line x1="400" y1="100" x2="431.72" y2="61.36" stroke-width="0.5" stroke="blue"/>
+ <line x1="400" y1="100" x2="435.4" y2="64.72" stroke-width="0.5" stroke="blue" />
+ <!-- line indicating the 3 'o clock starting point of the upper right circle -->
+ <line x1="400" y1="100" x2="450" y2="100" stroke-width="2" stroke="blue" />
+ <!-- lower right circle -->
+ <circle cx="400" cy="250" r="50" stroke-width="10" stroke-dasharray="305,15" stroke-linecap="round"/>
+ <!-- reference line lower right circle -->
+ <line x1="400" y1="250" x2="449.17" y2="240.88" stroke-width="0.5" stroke="blue"/>
+ <!-- line indicating the 3 'o clock starting point of lower right circle -->
+ <line x1="400" y1="250" x2="450" y2="250" stroke-width="2" stroke="blue"/>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-ellipse-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-ellipse-01-t.svg
new file mode 100644
index 0000000000..0268cc2f1b
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-ellipse-01-t.svg
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN" owner="KRL" desc="Test that viewer has the basic capability to handle the &lt;ellipse&gt; element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.10 $" testname="$RCSfile: shapes-ellipse-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-ellipse-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the &lt;ellipse /&gt; element with various stroke and fill attributes</text>
+ <!-- ====================================================================== -->
+ <!-- First pair of ellipses. -->
+ <!-- ====================================================================== -->
+ <ellipse xml:id="ellipse-01" fill="none" stroke="#000000" cx="50" cy="75" rx="30" ry="50" />
+ <ellipse xml:id="ellipse-02" fill="red" cx="160" cy="75" rx="30" ry="50" />
+ <!-- ====================================================================== -->
+ <!-- Second pair of ellipses, should actually draw circles. -->
+ <!-- ====================================================================== -->
+ <ellipse xml:id="ellipse-03" fill="none" stroke="#000000" cx="270" cy="80" rx="35" ry="35" />
+ <ellipse xml:id="ellipse-04" fill="red" cx="370" cy="80" rx="35" ry="35" />
+ <!-- ====================================================================== -->
+ <!-- Third pair of ellipses. -->
+ <!-- ====================================================================== -->
+ <ellipse xml:id="ellipse-05" fill="none" stroke="#0000FF" stroke-width="8" cx="50" cy="220" rx="30" ry="50" />
+ <ellipse xml:id="ellipse-06" fill="#00FF00" stroke="#0000FF" stroke-width="8" cx="160" cy="220" rx="30" ry="50" />
+ <!-- ====================================================================== -->
+ <!-- Fourth pair of ellipses. -->
+ <!-- ====================================================================== -->
+ <ellipse xml:id="ellipse-07" fill="#00FF00" stroke="#0000FF" stroke-width="8" cx="330" cy="220" rx="70" ry="40" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-ellipse-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-ellipse-02-t.svg
new file mode 100644
index 0000000000..2040890ff1
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-ellipse-02-t.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="DJ,AN" owner="CN" desc="Defaults test with ellipse." status="accepted"
+ approved="yes"
+ version="$Revision: 1.9 $" testname="$RCSfile: shapes-ellipse-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Defaults test with ellipse. Ellipses with rx or ry set to zero shouldn't be drawn. Unspecified cx and cy attributes default to zero.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-ellipse-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the default and zero value attributes of the &lt;ellipse /&gt; element.</text>
+ <g fill="red" stroke="#000000" fill-opacity="0.5">
+ <!-- Set cx and cy coordinate to default. Should be drawn at zero/zero. -->
+ <ellipse rx="100" ry="50" />
+ <!-- Set rx attribute to 0, ellipse shouldn't be drawn.-->
+ <ellipse cx="100" cy="150" rx="0" ry="50" />
+ <!-- Set ry attribute to 0, ellipse shouldn't be drawn.-->
+ <ellipse cx="200" cy="50" rx="100" ry="0" />
+ <!-- Set all values attribute to draw an ellipse.-->
+ <ellipse cx="250" cy="250" rx="100" ry="50" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g> -->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-ellipse-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-ellipse-03-t.svg
new file mode 100644
index 0000000000..6d024a84a7
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-ellipse-03-t.svg
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="AN" desc="Testing the correct stroking of the ellipse element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: shapes-ellipse-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Defaults test with circle.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-ellipse-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the correct stroking of the &lt;ellipse /&gt; element.</text>
+ <text font-size="12" x="160" y="106">3 'o clock starting point</text>
+ <text font-size="12" x="160" y="256">3 'o clock starting point</text>
+ <g fill="red" stroke="#000000">
+ <!-- upper left ellipse -->
+ <ellipse cx="100" cy="100" rx="50" ry="30" stroke-width="5" stroke-dasharray="50,5"/>
+ <!-- reference lines upper left ellipse -->
+ <line x1="100" y1="100" x2="113.78" y2="128.87" stroke-width="0.5" stroke="blue" />
+ <line x1="100" y1="100" x2="108.85" y2="129.55" stroke-width="0.5" stroke="blue" />
+ <line x1="100" y1="100" x2="61.07" y2="118.85" stroke-width="0.5" stroke="blue" />
+ <line x1="100" y1="100" x2="57.26" y2="115.6" stroke-width="0.5" stroke="blue" />
+ <line x1="100" y1="100" x2="69.41" y2="76.29" stroke-width="0.5" stroke="blue" />
+ <line x1="100" y1="100" x2="74.02" y2="74.38" stroke-width="0.5" stroke="blue" />
+ <line x1="100" y1="100" x2="123.2" y2="73.44" stroke-width="0.5" stroke="blue" />
+ <line x1="100" y1="100" x2="127.91" y2="75.13" stroke-width="0.5" stroke="blue" />
+ <!-- line indicating the 3 'o clock starting point for upper left ellipse-->
+ <line x1="100" y1="100" x2="150" y2="100" stroke-width="2" stroke="blue" />
+ <!-- lower left ellipse -->
+ <ellipse cx="100" cy="250" rx="50" ry="30" stroke-width="10" stroke-dasharray="245,15" />
+ <!-- reference line lower left ellipse -->
+ <line x1="100" y1="250" x2="147.31" y2="240.24" stroke-width="0.5" stroke="blue" />
+ <!-- line indicating the 3 'o clock starting point of lower left ellipse -->
+ <line x1="100" y1="250" x2="150" y2="250" stroke-width="2" stroke="blue" />
+ <!-- upper right ellipse -->
+ <ellipse cx="400" cy="100" rx="50" ry="30" stroke-width="5" stroke-dasharray="50,5" stroke-linecap="round"/>
+ <!-- reference lines upper left ellipse -->
+ <line x1="400" y1="100" x2="413.78" y2="128.87" stroke-width="0.5" stroke="blue" />
+ <line x1="400" y1="100" x2="408.85" y2="129.55" stroke-width="0.5" stroke="blue" />
+ <line x1="400" y1="100" x2="361.07" y2="118.85" stroke-width="0.5" stroke="blue" />
+ <line x1="400" y1="100" x2="357.26" y2="115.6" stroke-width="0.5" stroke="blue" />
+ <line x1="400" y1="100" x2="369.41" y2="76.29" stroke-width="0.5" stroke="blue" />
+ <line x1="400" y1="100" x2="374.02" y2="74.38" stroke-width="0.5" stroke="blue" />
+ <line x1="400" y1="100" x2="423.2" y2="73.44" stroke-width="0.5" stroke="blue" />
+ <line x1="400" y1="100" x2="427.91" y2="75.13" stroke-width="0.5" stroke="blue" />
+ <!-- line indicating the 3 'o clock starting point for upper right ellipse-->
+ <line x1="400" y1="100" x2="450" y2="100" stroke-width="2" stroke="blue" />
+ <!-- lower right ellipse -->
+ <ellipse cx="400" cy="250" rx="50" ry="30" stroke-width="10" stroke-dasharray="245,15" stroke-linecap="round"/>
+ <!-- reference line lower left ellipse -->
+ <line x1="400" y1="250" x2="447.31" y2="240.24" stroke-width="0.5" stroke="blue" />
+ <!-- line indicating the 3 'o clock starting point lower right -->
+ <line x1="400" y1="250" x2="450" y2="250" stroke-width="2" stroke="blue" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-intro-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-intro-01-t.svg
new file mode 100644
index 0000000000..129f3b6b19
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-intro-01-t.svg
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN,CN" owner="SH" desc="Test that viewer supports the degenerate cases of the basic shapes" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: shapes-intro-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Tests the degenerate cases of the basic shapes. The shapes are positioned within the black rectangles.</p>
+ <p>None of the shapes should be visible (each of the ten black rectangles should be empty). The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-intro-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the degenerate cases of the basic shapes; attribute values set to zero.</text>
+ <!-- ====================================================================== -->
+ <!-- Draw the boxes to contain the shapes and the text labels for the boxes -->
+ <!-- ====================================================================== -->
+ <g fill="none" stroke="#000000">
+ <!-- rects -->
+ <rect x="50" y="50" width="35" height="60" />
+ <rect x="50" y="155" width="35" height="60" />
+ <rect x="130" y="50" width="35" height="60" />
+ <rect x="130" y="155" width="35" height="60" />
+ <!-- circles -->
+ <rect x="210" y="50" width="60" height="60" />
+ <rect x="210" y="155" width="60" height="60" />
+ <!-- ellipses -->
+ <rect x="315" y="50" width="35" height="60" />
+ <rect x="315" y="155" width="35" height="60" />
+ <rect x="394" y="50" width="35" height="60" />
+ <rect x="394" y="155" width="35" height="60" />
+ <!-- line -->
+ <rect x="235" y="260" width="10" height="10" />
+ </g>
+ <g font-family="Arial" font-size="8">
+ <text x="5" y="90">Stroked</text>
+ <text x="5" y="195">Unstroked</text>
+ <text x="50" y="135">Zero width rect</text>
+ <text x="130" y="135">Zero height rect</text>
+ <text x="210" y="135">Zero radius circle</text>
+ <text x="315" y="135">Zero x radius ellipse</text>
+ <text x="394" y="135">Zero y radius ellipse</text>
+ <text x="235" y="290">Zero length line</text>
+ </g>
+ <!-- ====================================================================== -->
+ <!-- Draw 4 rectangles, two with zero width, two with zero height -->
+ <!-- (stroked and unstroked) -->
+ <!-- ====================================================================== -->
+ <rect xml:id="Zero-width-stroked-rect" fill="none" stroke="#000000" x="55" y="55" width="0" height="50" />
+ <rect xml:id="Zero-width-unstroked-rect" fill="#FF0000" stroke="none" x="55" y="160" width="0" height="50" />
+ <rect xml:id="Zero-height-stroked-rect" fill="#00FF00" stroke="#0000FF" x="135" y="55" width="25" height="0" />
+ <rect xml:id="Zero-height-rect" fill="#00FF00" stroke="none" x="135" y="160" width="25" height="0" />
+ <!-- ====================================================================== -->
+ <!-- Draw two zero radius circles (stroked and unstroked) -->
+ <!-- ====================================================================== -->
+ <circle xml:id="Zero-radius-stroked-circle" fill="none" stroke="#000000" cx="240" cy="80" r="0" />
+ <circle xml:id="Zero-radius-unstroked-circle" fill="#FF0000" stroke="none" cx="240" cy="185" r="0" />
+ <!-- ====================================================================== -->
+ <!-- Draw 4 ellipses, two with a zero x radius, two with a zero y radius -->
+ <!-- (stroked and unstroked) -->
+ <!-- ====================================================================== -->
+ <ellipse xml:id="Zero-x-radius-stroked-ellipse" fill="#00FF00" stroke="#0000FF" cx="332" cy="80" rx="0" ry="25" />
+ <ellipse xml:id="Zero-x-radius-unstroked-ellipse" fill="#00FF00" stroke="none" cx="332" cy="185" rx="0" ry="25" />
+ <ellipse xml:id="Zero-y-radius-stroked-ellipse" fill="none" stroke="#000000" cx="411" cy="80" rx="12" ry="0" />
+ <ellipse xml:id="Zero-y-radius-unstroked-ellipse" fill="#FF0000" stroke="none" cx="411" cy="185" rx="12" ry="0" />
+ <!-- ====================================================================== -->
+ <!-- Draw a zero-length line -->
+ <!-- ====================================================================== -->
+ <line xml:id="Zero-length-line" stroke="#0000FF" x1="240" y1="265" x2="240" y2="265" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-line-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-line-01-t.svg
new file mode 100644
index 0000000000..2d5e076938
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-line-01-t.svg
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN" owner="LH" desc="Test ability to handle the 'line' basic-shapes element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.9 $" testname="$RCSfile: shapes-line-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-line-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the &lt;line/&gt; element with different stroke and stroke-width attributes</text>
+ <g xml:id="diagonal-line-set">
+ <line x1="37.5" y1="137" x2="112.5" y2="50" fill="none" stroke="black" stroke-width="1" />
+ <line x1="112.5" y1="137" x2="187.5" y2="50" fill="none" stroke="red" stroke-width="5" />
+ <line x1="187.5" y1="137" x2="262.5" y2="50" fill="none" stroke="green" stroke-width="7.5" />
+ <line x1="262.5" y1="137" x2="337.5" y2="50" fill="none" stroke="blue" stroke-width="10" />
+ <line x1="337.5" y1="137" x2="412.5" y2="50" fill="none" stroke="fuchsia" stroke-width="12.5" />
+ </g>
+ <g xml:id="middle-figure" stroke="black" stroke-width="1">
+ <line x1="170" y1="200" x2="220" y2="200" />
+ <line x1="220" y1="200" x2="220" y2="250" />
+ <line x1="220" y1="250" x2="270" y2="250" />
+ <line x1="270" y1="250" x2="270" y2="200" />
+ <line x1="270" y1="200" x2="320" y2="200" />
+ </g>
+ <g xml:id="lower-left-figure" stroke="blue" stroke-width="10">
+ <line x1="25" y1="200" x2="75" y2="200" />
+ <line x1="75" y1="200" x2="75" y2="250" />
+ <line x1="75" y1="250" x2="125" y2="250" />
+ <line x1="125" y1="250" x2="125" y2="200" />
+ <line x1="125" y1="200" x2="175" y2="200" />
+ </g>
+ <g xml:id="lower-right-figure" stroke-width="10">
+ <line x1="370" y1="250" x2="420" y2="250" stroke="black" />
+ <line x1="420" y1="200" x2="470" y2="200" stroke="fuchsia" />
+ <line x1="320" y1="200" x2="370" y2="200" stroke="blue" />
+ <line x1="370" y1="200" x2="370" y2="250" stroke="green" />
+ <line x1="420" y1="250" x2="420" y2="200" stroke="red" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-line-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-line-02-t.svg
new file mode 100644
index 0000000000..cab56a93cc
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-line-02-t.svg
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="AN" desc="Test the default attributes of the line element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: shapes-line-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ For this test to pass the following lines must be drawn:
+ - Green line across the top from 480,0 to 0,0
+ - Red line across the left hand side from 0,0 to 0,360
+ - Blue line across the bottom from 480,360 to 0,360
+ - Purple line across the test from 480,85 to 0,0
+ - Fuchsia line across the test from 0,0 to 480,170
+ - Aqua line across the test from 0,360 to 480,170
+ - Teal line across the test from 480,256 to 0,360
+ </p>
+ <p>
+ If the x1, x2, y1, or y2 attribute is not specified the effect is as if
+ a value of "0" were specified.
+ </p>
+ <p>
+ The rendered picture should match the reference image, except for possible
+ variations in the labelling text (per CSS2 rules).
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-line-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the default attributes of the &lt;line/&gt; element</text>
+ <g stroke-width="4">
+ <line x2="480" y2="170" stroke="fuchsia"/>
+ <line y1="360" x2="480" y2="170" stroke="aqua"/>
+ <line x1="480" y1="85" stroke="purple"/>
+ <line x1="480" y1="256" y2="360" stroke="teal"/>
+ <line y2="360" stroke="red"/>
+ <line x1="480" stroke="green"/>
+ <line x1="480" y1="360" y2="360" stroke="blue"/>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polygon-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polygon-01-t.svg
new file mode 100644
index 0000000000..e6b6868903
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polygon-01-t.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN" owner="KRL" desc="Test that viewer has the basic capability to handle the 'polygon' element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.9 $" testname="$RCSfile: shapes-polygon-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-polygon-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the &lt;polygon/&gt; element with different fill, stroke and stroke-width attributes</text>
+ <!-- Test case label. -->
+ <!-- ====================================================================== -->
+ <!-- First two polygons, convex and "regular". -->
+ <!-- ====================================================================== -->
+ <!-- Open, convex, "regular". -->
+ <polygon xml:id="polygon-01" fill="none" stroke="#000000" points="59,45,95,63,108,105,82,139,39,140,11,107,19,65" />
+ <!-- Closed, convex, "regular". -->
+ <polygon xml:id="polygon-02" fill="red" points="179,45,218,63,228,105,202,139,159,140,131,107,139,65,179,45" />
+ <!-- ====================================================================== -->
+ <!-- Third polygon, concave and irregular. -->
+ <!-- ====================================================================== -->
+ <!-- Closed, convex, "irregular". -->
+ <polygon xml:id="polygon-03" fill="blue" stroke="black" stroke-width="6" points="350,45 375,80 410,95 375,110 350,145 325,120 290,95 325,70,350,45" />
+ <!-- ====================================================================== -->
+ <!-- Fourth and fifth polygons. -->
+ <!-- ====================================================================== -->
+ <!-- Closed, convex, "regular". -->
+ <polygon xml:id="polygon-05" fill="none" stroke="#0000FF" stroke-width="8" points="59,185,98,203,108,245,82,279,39,280,11,247,19,205,59,185" />
+ <!-- Open, convex, "regular". -->
+ <polygon xml:id="polygon-06" fill="#00FF00" stroke="#0000FF" stroke-width="8" points="179,185,218,203,228,245,202,279,159,280,131,247,139,205" />
+ <!-- ====================================================================== -->
+ <!-- Sixth polygons, irregular with both concave and convex angles. -->
+ <!-- ====================================================================== -->
+ <polygon xml:id="polygon-07" fill="none" stroke="#00FF00" stroke-width="8" points="270,225 300,245 320,225 340,245 280,280 390,280 420,240 280,185" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polygon-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polygon-02-t.svg
new file mode 100644
index 0000000000..763bf1b68c
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polygon-02-t.svg
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="AN" desc="Test points attribute syntax. Test that empty and invalid points attributes result in not rendering 'polygon' elements." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: shapes-polygon-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Testing different points attribute syntaxes, empty and invalid points
+ attributes (e.g. odd number of coordinates).
+ </p>
+ <p>
+ Only three identical polygon elements should be rendered down the
+ right hand side of the test.
+ </p>
+ <p>
+ The rendered picture should match the reference image, except for
+ possible variations in the labelling text (per CSS2 rules).
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-polygon-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Test that empty and invalid points attributes don't result in rendering 'polygon' elements.</text>
+ <text font-size="12" x="25" y="160">Only three similar &lt;polygon /&gt; elements should be rendered.</text>
+ <text font-size="12" x="25" y="180">Three different syntaxes in the points attribute.</text>
+ <!-- Test polygon without points attribute. -->
+ <polygon xml:id="polygon-01" fill="red" stroke="black" />
+ <!-- Test polygon with empty points attribute. -->
+ <polygon xml:id="polygon-02" fill="red" stroke="black" points="" />
+ <!-- odd number of coordinates -->
+ <polygon xml:id="polygon-03" fill="red" stroke="black" points="179,45,218,63,228,105,202,139,159,140,131,107,139,65,179" />
+ <!-- two alternative points attribute syntaxes -->
+ <polygon xml:id="polygon-04" fill="red" stroke="black" transform="translate(40,0)" points="350,45 375,80 410,95 375,110 350,145 325,120 290,95 325,70,350,45" />
+ <polygon xml:id="polygon-05" fill="red" stroke="black" transform="translate(40,100)" points="350,45,375,80,410,95,375,110,350,145,325,120,290,95,325,70,350,45" />
+ <polygon xml:id="polygon-06" fill="red" stroke="black" transform="translate(40,200)" points="350 45 375 80 410 95 375 110 350 145 325 120 290 95 325 70 350 45" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polyline-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polyline-01-t.svg
new file mode 100644
index 0000000000..904850cf15
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polyline-01-t.svg
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN" owner="LH" desc="Test that viewer has the basic capability to handle the 'polyline' element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.9 $" testname="$RCSfile: shapes-polyline-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-polyline-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the &lt;polyline/&gt; element with different fill, stroke and stroke-width attributes</text>
+ <!-- Test case label. -->
+ <!-- ====================================================================== -->
+ <!-- First two polylines. -->
+ <!-- ====================================================================== -->
+ <!-- Open sawtooth line. -->
+ <polyline xml:id="polyline-01" fill="none" stroke="#000000" points="10,50,35,150,60,50,85,150,110,50,135,150" />
+ <!-- text font-family="Arial" font-size="12" x="52" y="40">stroked</text-->
+ <!-- Closed pentagon shaped polyline (5 segments). -->
+ <polyline xml:id="polyline-02" fill="none" stroke="blue" stroke-width="8" points="220,50,267,84,249,140,190,140,172,84,220,50" />
+ <!--text font-family="Arial" font-size="12" x="202" y="40">stroked</text-->
+ <!-- ====================================================================== -->
+ <!-- Third polyline. -->
+ <!-- ====================================================================== -->
+ <!-- The sawtooth again, polylines can be filled. -->
+ <polyline xml:id="polyline-03" fill="blue" stroke="#00FF00" stroke-width="4" points="310,50,335,150,360,50,385,150,410,50,435,150" />
+ <!--text font-family="Arial" font-size="12" x="340" y="40">filled &amp; stroked</text-->
+ <!-- ====================================================================== -->
+ <!-- Fourth and fifth polylines. -->
+ <!-- ====================================================================== -->
+ <!-- An unclosed "septagon" shaped polyline (7th segment omitted). -->
+ <polyline xml:id="polyline-04" fill="none" stroke="red" stroke-width="8" points="59,185,98,203,108,245,82,279,39,280,11,247,19,205" />
+ <!--text font-family="Arial" font-size="12" x="36" y="175">stroked</text-->
+ <!-- Same shape, filled, shows difference with 'polygon'. -->
+ <polyline xml:id="polyline-05" fill="#00FF00" stroke="#0000FF" stroke-width="8" points="189,185,228,203,238,245,212,279,169,280,141,247,149,205" />
+ <!--text font-family="Arial" font-size="12" x="148" y="175">filled &amp; stroked</text-->
+ <!-- ====================================================================== -->
+ <!-- Sixth polylines, irregular with both concave and convex angles. -->
+ <!-- ====================================================================== -->
+ <polyline xml:id="polyline-06" fill="#FF00FF" stroke="none" stroke-width="8" points="270,225 300,245 320,225 340,245 280,280 390,280 420,240 280,185" />
+ <!--text font-family="Arial" font-size="12" x="330" y="175">filled</text-->
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polyline-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polyline-02-t.svg
new file mode 100644
index 0000000000..3eb4771000
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-polyline-02-t.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="AN" desc="Test points attribute syntax. Test that empty and invalid points attributes result in not rendering 'polyline' elements." status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: shapes-polyline-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Testing different points attribute syntaxes, empty and invalid points
+ attributes (e.g. odd number of coordinates).
+ </p>
+ <p>
+ Only three identical polygon elements should be rendered down the
+ right hand side of the test.
+ </p>
+ <p>
+ The rendered picture should match the reference image, except for possible
+ variations in the labelling text (per CSS2 rules).
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-polyline-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Test that empty and invalid points attributes result in not rendering &lt;polyline /&gt; elements.</text>
+ <text font-size="12" x="25" y="160">Only three similar &lt;polyline /&gt; elements should be rendered.</text>
+ <text font-size="12" x="25" y="180">Two different syntaxes in the points attribute.</text>
+ <!-- Test polyline without points attribute. -->
+ <polyline xml:id="polyline-01" fill="red" stroke="black" />
+ <!-- Test polyline with empty points attribute. -->
+ <polyline xml:id="polyline-02" fill="red" stroke="black" points="" />
+ <!-- odd number of coordinates -->
+ <polyline xml:id="polyline-03" fill="red" stroke="black" points="179,45,218,63,228,105,202,139,159,140,131,107,139,65,179" />
+ <!-- three alternative points attribute syntaxes -->
+ <polyline xml:id="polyline-04" fill="red" stroke="black" transform="translate(40,0)" points="350,45 375,80 410,95 375,110 350,145 325,120 290,95 325,70,350,45" />
+ <polyline xml:id="polyline-05" fill="red" stroke="black" transform="translate(40,100)" points="350,45,375,80,410,95,375,110,350,145,325,120,290,95,325,70,350,45" />
+ <polyline xml:id="polyline-06" fill="red" stroke="black" transform="translate(40,200)" points="350 45 375 80 410 95 375 110 350 145 325 120 290 95 325 70 350 45" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-rect-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-rect-01-t.svg
new file mode 100644
index 0000000000..52fc61551a
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-rect-01-t.svg
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AN" owner="KRL" desc="Test that viewer has the basic capability to handle the &lt;rect&gt; element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.10 $" testname="$RCSfile: shapes-rect-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-rect-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the &lt;rect/&gt; element with different fill, stroke and rx attributes</text>
+ <!-- ====================================================================== -->
+ <!-- First of all draw two simple rectangles. One stroked, one filled. -->
+ <!-- ====================================================================== -->
+ <rect xml:id="Simple-rect-no-fill" fill="none" stroke="#000000" x="30" y="46" width="50" height="80" />
+ <rect xml:id="Simple-rect-filled" fill="red" x="130" y="46" width="50" height="80" />
+ <!-- ====================================================================== -->
+ <!-- Second set of rectangles this time with rounded corners. -->
+ <!-- ====================================================================== -->
+ <rect xml:id="Simple-round-rect-no-fill" fill="none" stroke="#000000" x="250" y="46" width="50" height="80" rx="30" />
+ <rect xml:id="Simple-round-rect-filled" fill="red" x="350" y="46" width="50" height="80" rx="30" />
+ <!-- ====================================================================== -->
+ <!-- Third set of rectangles. -->
+ <!-- ====================================================================== -->
+ <rect xml:id="rect-03" fill="none" stroke="#0000FF" stroke-width="8" x="30" y="196" width="50" height="80" />
+ <rect xml:id="rect-04" fill="#00FF00" stroke="#0000FF" stroke-width="8" x="130" y="196" width="50" height="80" />
+ <!-- ====================================================================== -->
+ <!-- Fourth set of rectangles. -->
+ <!-- ====================================================================== -->
+ <rect xml:id="rect-05" fill="none" stroke="#0000FF" stroke-width="8" x="250" y="196" width="50" height="80" rx="30" ry="50" />
+ <rect xml:id="rect-06" fill="#00FF00" x="350" y="196" width="50" height="80" rx="30" ry="50" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-rect-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-rect-02-t.svg
new file mode 100644
index 0000000000..4a590c2300
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-rect-02-t.svg
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="DJ,AN" owner="CN" desc="Testing the default attributes on the rect element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.9 $" testname="$RCSfile: shapes-rect-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ <p>Testing the default attributes on the rect element. There should be four rectangles. One should be placed on the left (default x), one on the top (default y). Two rounded rectangles should appear where rx and ry are of the same value (one of the two had been omitted).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-rect-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the default values of attributes of the &lt;rect/&gt; element</text>
+ <g fill="blue" stroke="#000000" fill-opacity="0.5">
+ <!-- Set x coordinate to default. -->
+ <rect y="46" width="50" height="80" />
+ <!-- Set y coordinate to default. -->
+ <rect x="130" width="50" height="80" />
+ <!-- Set width to default. -->
+ <rect x="250" y="46" height="80" width="0" />
+ <!-- Set height to default. -->
+ <rect x="350" y="46" height="0" width="50" />
+ <!-- Set rx to default. -->
+ <rect x="30" y="196" width="50" height="80" ry="20" />
+ <!-- Set ry to default. -->
+ <rect x="130" y="196" width="50" height="80" rx="20" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-rect-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-rect-03-t.svg
new file mode 100644
index 0000000000..1eb14fb8d8
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/shapes-rect-03-t.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="AN" desc="Testing the correct stroking of the rect element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: shapes-rect-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Testing the correct stroking of the rect element. The blue lines indicate where a dash or gap should start and end. For the test to pass, it has to match the reference image.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: shapes-rect-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" x="240" y="14" text-anchor="middle">Testing the correct stroking of the &lt;rect/&gt; element</text>
+ <g fill="red" stroke="#000000">
+ <!-- normal rectangle -->
+ <rect x="50" y="100" width="100" height="100" stroke-dasharray="100,5" stroke-width="5"/>
+ <!-- rectangle with rounded corner -->
+ <rect x="250" y="100" width="100" height="100" rx="10" ry="10" stroke-dasharray="100,5" stroke-width="5"/>
+ </g>
+ <g xml:id="lines_indicating_the_dashing" stroke="blue">
+ <!-- left rectangle -->
+ <line x1="50" y1="100" x2="50" y2="90" />
+ <line x1="150" y1="100" x2="150" y2="90" />
+ <line x1="150" y1="105" x2="160" y2="105" />
+ <line x1="145" y1="200" x2="145" y2="210" />
+ <line x1="140" y1="200" x2="140" y2="210" />
+ <line x1="50" y1="190" x2="40" y2="190" />
+ <line x1="50" y1="185" x2="40" y2="185" />
+ <!-- right rectangle -->
+ <line x1="260" y1="100" x2="260" y2="90" />
+ <line x1="350" y1="114" x2="360" y2="114" />
+ <line x1="350" y1="119" x2="360" y2="119" />
+ <line x1="326.4" y1="200" x2="326.4" y2="210" />
+ <line x1="321.4" y1="200" x2="321.4" y2="210" />
+ <line x1="250" y1="167" x2="240" y2="167" />
+ <line x1="250" y1="162" x2="240" y2="162" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark" fill-opacity="0.5">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-class-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-class-201-t.svg
new file mode 100644
index 0000000000..b1a1cb6ba2
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-class-201-t.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events" xml:space="preserve">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="DS" desc="Tests that the value of the 'class' attribute is included in the DOM" status="accepted"
+ approved="yes"
+ version="$Revision: 1.3 $" testname="$RCSfile: struct-class-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Tests that the value of the 'class' attribute is included in the DOM,
+ including space-separated values, and values with extraneous spaces.
+ </p>
+ <p>
+ The rendered picture should match the reference image, except for
+ possible variations in the labelling text (per CSS2 rules). The pass
+ condition is seeing three green circles, with text below each circle
+ reflecting the normalized space-separated values for the class of that
+ circle. The leftmost circle has the value "foo", the middle circle has
+ the value "bar baz", and the rightmost circle has the value
+ " funky spacing ", normalized to "funky spacing". If any of the
+ circles are red, the test has failed.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-class-201-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <circle xml:id="circle_1" cx="120" cy="150" r="40" class="foo" />
+ <text id="text_1" x="120" y="210" font-size="18" fill="black" text-anchor="middle"> </text>
+
+ <circle xml:id="circle_2" cx="240" cy="150" r="40" class="bar baz" />
+ <text id="text_2" x="240" y="210" font-size="18" fill="black" text-anchor="middle"> </text>
+
+ <circle xml:id="circle_3" cx="360" cy="150" r="40" class=" funky spacing " />
+ <text id="text_3" x="360" y="210" font-size="18" fill="black" text-anchor="middle"> </text>
+
+ <script type="text/ecmascript">
+ <![CDATA[
+ function testAttributeValue( targetElId, outputElId, val )
+ {
+ var targetEl = document.getElementById( targetElId );
+
+ var classVal = targetEl.getAttribute( "class" );
+ //normalize value
+ classVal = classVal.replace(/^\s+|\s+$/g,"").replace(/\s+/g," ");
+
+ var fill = "red";
+ if ( classVal == val )
+ {
+ fill = "lime";
+ }
+ targetEl.setAttribute( "fill", fill );
+
+ var outputEl = document.getElementById( outputElId );
+ outputEl.firstChild.nodeValue = classVal;
+ }
+
+ testAttributeValue("circle_1", "text_1", "foo");
+ testAttributeValue("circle_2", "text_2", "bar baz");
+ testAttributeValue("circle_3", "text_3", "funky spacing");
+ ]]>
+ </script>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.3 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-common-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-common-201-t.svg
new file mode 100644
index 0000000000..e758029040
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-common-201-t.svg
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <handler type="application/ecmascript" xe:event="SVGLoad">
+ initTest(evt);
+ </handler>
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="CL" desc="test id and xml:id modification" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: struct-common-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Tests that reading of IDs and modification of id and xml:id is conformant to the SVG and xml:id specifications. The test passes if four green circles are shown.
+ </p>
+ <p>
+ The first circle has an id only; the second, xml:id only. The third circle has both, with the same values; and the fourth has both, with different values. All four circles have a red fill; on loading the document, a script
+ gets each of the circles by its ID and then sets the fill to green. Lastly, the script attempts
+ to get the fourth circle by ID, using the value of the id attribute; this must fail. If the fourth
+ circle is dark red, the implementation is not giving priority to the value of xml:id.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-common-201-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <script type="application/ecmascript">
+ <![CDATA[
+ var svg_ns = "http://www.w3.org/2000/svg"
+ var doc;
+ var oldid;
+ var newid;
+ var bothids;
+ var different;
+
+ //
+ // onload handler for top level svg element.
+ //
+ function initTest(evt)
+ {
+ // Get Document
+ var target = evt.target;
+ doc = target.ownerDocument;
+
+ // Get elements identified by id, by xml:id, and by both
+ oldid = doc.getElementById("cod");
+ newid= doc.getElementById("plaice");
+ bothids= doc.getElementById("flounder");
+ different= doc.getElementById("mackerel");
+
+ //Make all four elements green
+ oldid.setAttribute("fill", "green");
+ newid.setAttribute("fill", "green");
+ bothids.setAttribute("fill", "green");
+ different.setAttribute("fill", "green");
+
+ //Try to select on id, should fail
+ different= doc.getElementById("herring");
+ different.setAttribute("fill", "#700");
+
+ }
+ ]]>
+ </script>
+
+ <circle cx="60" cy="100" r="50" fill="red" id="cod"/>
+ <circle cx="180" cy="100" r="50" fill="red" xml:id="plaice" />
+ <circle cx="300" cy="100" r="50" fill="red" id="flounder" xml:id="flounder"/>
+ <circle cx="420" cy="100" r="50" fill="red" id="herring" xml:id="mackerel"/>
+
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="16" text-anchor="middle">
+ <text x="60" y="190">id only</text>
+ <text x="180" y="190">xml:id only</text>
+ <text x="300" y="190">id and</text>
+ <text x="300" y="210">xml:id, same</text>
+ <text x="300" y="230">values</text>
+ <text x="420" y="190">id and</text>
+ <text x="420" dy="210">xml:id, different</text>
+ <text x="420" dy="230">values</text>
+ </g>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--
+ <g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>
+ -->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-01-t.svg
new file mode 100644
index 0000000000..91f8851c87
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-01-t.svg
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="TT" desc="Test to determine if a simple switch element can be probably evaluated." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: struct-cond-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test evaluates a switch statement. The result should be a green rectangle in the lower left quarter of the output window.</p>
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ <p>The test uses the 'rect' element, as well as basic fill (solid primary colors), stroke (black 1-pixel lines), font-family (Arial) and font-size properties.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-cond-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <switch>
+ <rect fill="red" x="0" y="0" width="220" height="150" requiredExtensions="http://example.org/bogus" />
+ <rect fill="green" x="0" y="150" width="220" height="150" />
+ <rect fill="blue" x="240" y="0" width="220" height="150" />
+ </switch>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-02-t.svg
new file mode 100644
index 0000000000..ce35c1a25f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-02-t.svg
@@ -0,0 +1,336 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="CL" desc="Test that viewer has the basic capability to switch on user langauge" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: struct-cond-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This tests ability to use the 'systemLanguage' as a test attribute within a switch element. To pass, either</p>
+ <p>It is an error to display no output; the last child of switch has no test, so it will always be taken unless a more suitable child has already evaluated to true.</p>
+ <p>In addition, the string "Why don't they just speak &lt;language&gt;" should appear in the center of the graphic, translated into that language. It is not an error for some or all of this string to display as 'missing character' glyphs, if no suitable font is available - however, this is unlikely if the language is indeed the users primary language. (It can easily occur during testing, however).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-cond-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g fill="black" stroke="none" font-size="24" font-weight="normal" font-family="Arial, Tahoma, Verdana, 'Arial Unicode MS', Code2000">
+ <!-- a blank one <text x="20" y="220" xml:lang=""> <tspan font-weight="bold" > ?</text> <text x="230" y="150" xml:lang="en"></text> -->
+ <!-- put sample here for testing -->
+ <switch>
+ <g systemLanguage="af">
+ <text x="20" y="220" xml:lang="af" font-size="16">Waarom kan hulle nie net doodgewoon Afrikaans praat nie?</text>
+ <text x="230" y="150" xml:lang="en">Afrikaans</text>
+ </g>
+ <g systemLanguage="am">
+ <text x="20" y="220" xml:lang="am" font-family="'GF Zemen Unicode',Code2000" font-size="28">ለምንድነው አማርኛ የማይናገሩት፧</text>
+ <text x="230" y="150" xml:lang="en">Amharic</text>
+ </g>
+ <g systemLanguage="ar">
+ <!-- this is a tiny test so there is no text-anchor, thus rtl text is explicitly positioned -->
+ <text x="20" y="220" xml:lang="ar-SA" font-family=" Tahoma,'MS Farsi','Arial Unicode MS'" font-size="19">لماذا لا يتكلمون اللّغة العربية فحسب؟</text>
+ <text x="230" y="150" xml:lang="en">Arabic (SA)</text>
+ </g>
+ <g systemLanguage="bg">
+ <text x="20" y="220" xml:lang="bg" font-size="18">Защо те просто не могат да говорят български ?</text>
+ <text x="230" y="150" xml:lang="en">Bulgarian</text>
+ </g>
+ <g systemLanguage="bn">
+ <text x="20" y="220" xml:lang="bn" font-family="'Arial Unicode MS','UT Bengali Khulna'" font-size="28">ওরা েকন বাংলা বলেত পাের না ?</text>
+ <text x="230" y="150" xml:lang="en">Bengali</text>
+ </g>
+ <!-- Tibetan needs complex layout: this will not work correctly though the font has the right glyphs: <g systemLanguage="bo"> <text x="20" y="220" xml:lang="bo" font-family="'Arial Unicode MS'" font-size="18"> ག་རེ་བྱས་ཁོ་རང་ཚོས་ བོད་ སྐད་ཆ་དེ་ག་རང་བཤད་ཀྱི་མ་རེད།</text> <text x="230" y="150" xml:lang="en">Tibetan</text> </g>-->
+ <g systemLanguage="ca">
+ <text x="20" y="220" xml:lang="bg" font-size="20">Per què no poden simplement parlar en català ?</text>
+ <text x="230" y="150" xml:lang="en">Catalan</text>
+ </g>
+ <g systemLanguage="cs">
+ <text x="20" y="220" xml:lang="cs">Proč prostě nemluví česky ?</text>
+ <text x="230" y="150" xml:lang="en">Czech</text>
+ </g>
+ <g systemLanguage="cy">
+ <text x="20" y="220" xml:lang="cy" font-size="20">Pam dydyn nhw ddim yn siarad Cymraeg ?</text>
+ <text x="230" y="150" xml:lang="en">Welsh</text>
+ </g>
+ <g systemLanguage="da">
+ <text x="20" y="220" xml:lang="da">Hvorfor kan de ikke bare tale dansk ?</text>
+ <text x="230" y="150" xml:lang="en">Danish</text>
+ </g>
+ <!-- need a generic german, too -->
+ <g systemLanguage="de-DE">
+ <text x="20" y="220" xml:lang="de-DE" font-size="22">Warum sprechen sie nicht einfach Deutsch ?</text>
+ <text x="230" y="150" xml:lang="en">German (DE)</text>
+ </g>
+ <g systemLanguage="el">
+ <text x="20" y="220" xml:lang="el-GR" font-size="22">Μα γιατί δεν μπορούν να μιλήσουν Ελληνικά ;</text>
+ <text x="230" y="150" xml:lang="en">Greek (modern, GR)</text>
+ </g>
+ <g systemLanguage="en">
+ <text x="20" y="220" xml:lang="en-US">Why can't they just speak English ?</text>
+ <text x="230" y="150" xml:lang="en">English (US)</text>
+ </g>
+ <g systemLanguage="es">
+ <text x="20" y="220" xml:lang="es-ES" font-size="18">¿Por qué no pueden simplemente hablar en castellano ?</text>
+ <text x="230" y="150" xml:lang="en">Spanish (ES)</text>
+ </g>
+ <g systemLanguage="eu">
+ <text x="20" y="220" xml:lang="eu" font-size="21">Zergatik ezin dute  Euzkeraz bakarrik hitzegin?</text>
+ <text x="230" y="150" xml:lang="en">Basque</text>
+ </g>
+ <g systemLanguage="fa">
+ <text x="20" y="220" xml:lang="fa" font-family=" Tahoma,'MS Farsi','Arial Unicode MS'" font-size="22">خب، چرا فارسى صحبت نمى كنند؟</text>
+ <text x="230" y="150" xml:lang="en">Farsi</text>
+ </g>
+ <g systemLanguage="fi">
+ <text x="20" y="220" xml:lang="fi" font-size="20">Miksi he eivät yksinkertaisesti puhu suomea ?</text>
+ <text x="230" y="150" xml:lang="en">Finnish</text>
+ </g>
+ <!-- put Canadian French before generic French -->
+ <g systemLanguage="fr">
+ <text x="20" y="220" xml:lang="fr-fR" font-size="17">Pourquoi, tout simplement, ne parlent-ils pas en Français ?</text>
+ <text x="230" y="150" xml:lang="en">French (FR)</text>
+ </g>
+ <g systemLanguage="gd">
+ <text x="20" y="220" xml:lang="gd" font-size="20">Carson nach eil iad a'bruidhinn na Gàidhlige ?</text>
+ <text x="230" y="150" xml:lang="en">Scots Gaelic</text>
+ </g>
+ <g systemLanguage="gu">
+ <text x="20" y="220" xml:lang="gu" font-family="'Arial Unicode MS'" font-size="28">બદ્ધા લોકો ગુજરાતી કૅમ નથી બોલતા?</text>
+ <text x="230" y="150" xml:lang="en">Gujarti (IN)</text>
+ </g>
+ <g systemLanguage="he">
+ <!-- he or iw, check -->
+ <text x="20" y="220" xml:lang="he" font-family="Tahoma,'Arial Unicode MS'" font-size="22">למה הם פשוט לא מדברים עברית ?</text>
+ <text x="230" y="150" xml:lang="en">Hebrew (modern)</text>
+ </g>
+ <g systemLanguage="hi">
+ <text x="20" y="220" xml:lang="hi" font-family="Mangal,Code2000,'Arial Unicode MS'">यह लोग हिन्दी क्यों नहीं बोल सकते हैं ?</text>
+ <text x="230" y="150" xml:lang="en">Hindi</text>
+ </g>
+ <g systemLanguage="hr">
+ <text x="20" y="220" xml:lang="hr">Zašto jednostavno ne govore hrvatski ?</text>
+ <text x="230" y="150" xml:lang="en">Croatian</text>
+ </g>
+ <g systemLanguage="hu">
+ <text x="20" y="220" xml:lang="hu" font-size="22">Miért nem beszélnek egyszerűen magyarul ?</text>
+ <text x="230" y="150" xml:lang="en">Hungarian</text>
+ </g>
+ <g systemLanguage="hy">
+ <text x="20" y="220" xml:lang="hy" font-family="Sylfaen,Code2000,'Arial Unicode MS'" font-size="22">Ինչու՞ նրանք չեն խոսում Հայերեն </text>
+ <text x="230" y="150" xml:lang="en">Armenian</text>
+ </g>
+ <g systemLanguage="id">
+ <text x="20" y="220" xml:lang="id" font-size="18">Mengapa mereka tidak bisa bicara bahasa Indonesia ?</text>
+ <text x="230" y="150" xml:lang="en">Indonesian</text>
+ </g>
+ <g systemLanguage="is">
+ <text x="20" y="220" xml:lang="is" font-size="20">Hvers vegna geta þeir ekki réttlátur tala Íslenska ?</text>
+ <text x="230" y="150" xml:lang="en">Icelandic</text>
+ </g>
+ <g systemLanguage="it">
+ <text x="20" y="220" xml:lang="it" font-size="18">Perchè non possono semplicemente parlare italiano ?</text>
+ <text x="230" y="150" xml:lang="en">Italian</text>
+ </g>
+ <g systemLanguage="iu">
+ <!-- unable to distinguish North Baffin Island Inuktitut from South/Central Baffin Island Inuktitut because ISO 3166 codes do not offer any finer resolution than 'Canadian' -->
+ <text x="20" y="220" xml:lang="iu" font-family="NunacomU,'Ballymun RO','Arial Unicode MS'" font-size="28">ᓱᒻᒪᓂᒃᑯᐊ ᐃᓄᒃᑎᑐ ᑐᐃᓐᓇᔭᙱᓚᑦ</text>
+ <text x="230" y="150" xml:lang="en">Inuktitut</text>
+ </g>
+ <g systemLanguage="ja-JP">
+ <text x="20" y="220" xml:lang="ja-JP" font-family="'MS Gothic',MS ゴシック,'MS Mincho',MS 明朝,Code2000,'Arial Unicode MS',DFP-SMTWSong" font-size="22">なぜ、みんな日本語を話してくれないのか?</text>
+ <text x="230" y="150" xml:lang="en">Japanese (JP)</text>
+ </g>
+ <g systemLanguage="jw">
+ <text x="20" y="220" xml:lang="jw" font-size="20">Kenapa kok ora nganggo  basa Jawa  wae?</text>
+ <text x="230" y="150" xml:lang="en">Javanese</text>
+ </g>
+ <g systemLanguage="ka">
+ <text x="20" y="220" xml:lang="ka" font-family="Sylfaen,Code2000,'Arial Unicode MS'" font-size="20">რატომ არ ლაპარაკობენ ისინი ქართულად ?</text>
+ <text x="230" y="150" xml:lang="en">Georgian</text>
+ </g>
+ <g systemLanguage="kk">
+ <text x="20" y="220" xml:lang="kk" font-family="'Arial Unicode MS',Code2000">Олар неге қазақ тiлiнде сойлемейдi?</text>
+ <text x="230" y="150" xml:lang="en">Kazakh</text>
+ </g>
+ <g systemLanguage="kn">
+ <text x="20" y="220" xml:lang="kn" font-family="'Arial Unicode MS',Code2000" font-size="28">ಅವರು ಕನ್ನಡ ಮಾತನಾಡಬಹುದಲ್ಲಾ?</text>
+ <text x="230" y="150" xml:lang="en">Kannada</text>
+ </g>
+ <g systemLanguage="ko">
+ <text x="20" y="220" xml:lang="ko" font-family="GulimChe,굴림체,Gulim,굴림,BatangChe,바탕체,Batang,바탕,Code2000,'Arial Unicode MS'" font-size="15">세계의 모든 사람들이 한국어 를 이해한다면 얼마나 좋을까?</text>
+ <text x="230" y="150" xml:lang="en">Korean</text>
+ </g>
+ <g systemLanguage="ky">
+ <text x="20" y="220" xml:lang="ky" font-family="'Arial Unicode MS',Code2000">Емне үчүн алар кыргызча сүйлбйт?</text>
+ <text x="230" y="150" xml:lang="en">Kirghiz</text>
+ </g>
+ <g systemLanguage="lt">
+ <text x="20" y="220" xml:lang="lt" font-size="28">Kodėl gi jie nekalba lietuviškai ?</text>
+ <text x="230" y="150" xml:lang="en">Lithuanian</text>
+ </g>
+ <g systemLanguage="mk">
+ <text x="20" y="220" xml:lang="mk" font-size="20">Зошто тие едноставно не говорат македонски ?</text>
+ <text x="230" y="150" xml:lang="en">Macedonian</text>
+ </g>
+ <g systemLanguage="mr">
+ <text x="20" y="220" xml:lang="mr" font-family="Mangal,Code2000,'Arial Unicode MS'" font-size="26">लोकांना मराठी का बोलता येत नाही?</text>
+ <text x="230" y="150" xml:lang="en">Marathi</text>
+ </g>
+ <g systemLanguage="nl">
+ <text x="20" y="220" xml:lang="nl" font-size="21">Waarom spreken ze niet gewoon Nederlands ?</text>
+ <text x="230" y="150" xml:lang="en">Dutch</text>
+ </g>
+ <g systemLanguage="no">
+ <text x="20" y="220" xml:lang="no" font-size="21">Hvorfor kan de ikke bare snakke norsk ?</text>
+ <text x="230" y="150" xml:lang="en">Norwegian</text>
+ </g>
+ <g systemLanguage="or">
+ <text x="20" y="220" xml:lang="or" font-family="'Arial Unicode MS',Code2000" font-size="26">ସେମାନେ ଉଡିଯା ରେ କହିନ୍କି କହିବେ ନହିଁ?</text>
+ <text x="230" y="150" xml:lang="en">Oriya</text>
+ </g>
+ <g systemLanguage="pl">
+ <text x="20" y="220" xml:lang="pl">Dlaczego oni nie mówią po polsku ?</text>
+ <text x="230" y="150" xml:lang="en">Polish</text>
+ </g>
+ <!-- test two specific types of Portugese, then a generic alternative -->
+ <g systemLanguage="pt-PT">
+ <text x="20" y="220" xml:lang="pt-PT" font-size="18">Porque é que eles não falam simplesmente em Português ?</text>
+ <text x="230" y="150" xml:lang="en">Portugese (PT)</text>
+ </g>
+ <g systemLanguage="pt-BR">
+ <text x="20" y="220" xml:lang="pt-BR" font-size="17">Porque é que eles não falam em Português (do Brasil) ?</text>
+ <text x="230" y="150" xml:lang="en">Portugese (BR)</text>
+ </g>
+ <g systemLanguage="pt">
+ <text x="20" y="220" xml:lang="pt-PT" font-size="18">Porque é que eles não falam simplesmente em Português ?</text>
+ <text x="230" y="150" xml:lang="en">Portugese</text>
+ </g>
+ <g systemLanguage="ro">
+ <text x="20" y="220" xml:lang="ro">De ce ei nu vorbesc moldoveneşte ?</text>
+ <text x="230" y="150" xml:lang="en">Romanian</text>
+ </g>
+ <g systemLanguage="ru">
+ <text x="20" y="220" xml:lang="ru">Почему же они не говорят по-русски ?</text>
+ <text x="230" y="150" xml:lang="en">Russian</text>
+ </g>
+ <g systemLanguage="sa">
+ <text x="20" y="220" xml:lang="sa" font-family="Mangal,Code2000,'Arial Unicode MS'" font-size="26">ते किं संस्कृतः माम वदन्ति ?</text>
+ <text x="230" y="150" xml:lang="en">Sanskrit</text>
+ </g>
+ <g systemLanguage="sr">
+ <text x="20" y="220" xml:lang="sr">Zašto jednostavno ne govore srpski ?</text>
+ <text x="230" y="150" xml:lang="en">Serbian</text>
+ </g>
+ <g systemLanguage="si">
+ <text x="20" y="220" xml:lang="si" font-family="'Andale Mono WT J'" font-size="26">අැයි ඔවුන්ට ඉංගරිස කතා ෛනබ ?</text>
+ <text x="230" y="150" xml:lang="en">Sinhalese</text>
+ <!-- Sinhalese needs somewhat complex layout (many paired special cases, see http://www-texdev.mpce.mq.edu.au/l2h/indic/Sinhala/lreport/node1.html so this 'chart' font is not entirely suitable-->
+ </g>
+ <g systemLanguage="sl">
+ <text x="20" y="220" xml:lang="sl">Zakaj vendar ne govorijo slovensko ?</text>
+ <text x="230" y="150" xml:lang="en">Slovenian</text>
+ </g>
+ <g systemLanguage="sq">
+ <text x="20" y="220" xml:lang="sq">Pse nuk duan të flasin vetëm shqip ?</text>
+ <text x="230" y="150" xml:lang="en">Albanian</text>
+ </g>
+ <g systemLanguage="sv">
+ <text x="20" y="220" xml:lang="sv">Varför pratar dom inte bara svenska ?</text>
+ <text x="230" y="150" xml:lang="en">Swedish</text>
+ </g>
+ <g systemLanguage="ta">
+ <text x="20" y="220" xml:lang="ta" font-family="Latha,'Arial Unicode MS'" font-size="20">அவர்கள் ஏன் தமிழில் பேசக்கூடாது ?</text>
+ <text x="230" y="150" xml:lang="en">Tamil</text>
+ </g>
+ <g systemLanguage="te">
+ <text x="20" y="220" xml:lang="te" font-family="'Arial Unicode MS'"> తెలుగు లో ఎందుకు మాట్లాడరు?</text>
+ <text x="230" y="150" xml:lang="en">Telugu</text>
+ </g>
+ <g systemLanguage="tg">
+ <text x="20" y="220" xml:lang="tg" font-size="20">Čaro onho ba zaboni točiki gap namezanand?</text>
+ <text x="230" y="150" xml:lang="en">Tajik</text>
+ </g>
+ <g systemLanguage="th">
+ <text x="20" y="220" xml:lang="th" font-family="Tahoma,CordiaUPC,BrowalliaUPC,DilleniaUPC,EucrosiaUPC,FreesiaUPC,JasmineUPC, KodChiangUPC,LilyUPC,'Arial Unicode MS'" font-size="28">ทำไมเขาถึงไม่พูด ภาษาไทย </text>
+ <text x="230" y="150" xml:lang="en">Thai</text>
+ </g>
+ <g systemLanguage="tl">
+ <text x="20" y="220" xml:lang="tl" font-size="19">Bakit hindi na lang sila magsalita ng Tagalog ?</text>
+ <text x="230" y="150" xml:lang="en">Tagalog (Filipino)</text>
+ </g>
+ <g systemLanguage="tr">
+ <text x="20" y="220" xml:lang="tr">Neden Türkçe konuşamıyorlar?</text>
+ <text x="230" y="150" xml:lang="en">Turkish</text>
+ </g>
+ <g systemLanguage="tt">
+ <text x="20" y="220" xml:lang="tt" font-family="'Arial Unicode MS',Code2000" font-size="22">Нишләп олар татарча сүләша алмыйлар?</text>
+ <text x="230" y="150" xml:lang="en">Tatar</text>
+ </g>
+ <g systemLanguage="uk">
+ <text x="20" y="220" xml:lang="uk">Чому б їм не розмовляти українською ?</text>
+ <text x="230" y="150" xml:lang="en">Ukranian</text>
+ </g>
+ <g systemLanguage="ur-IN">
+ <text x="20" y="220" xml:lang="ur-IN" font-family=" Tahoma,'MS Farsi','Arial Unicode MS'" font-size="22">ﻦﻴﻫ ﻰﺘﻠﻭﺒ ﻦﻴﻬﻨ ﻦﻭﻴﻜ ﻮﺪﺭﺃ بس ﻮﻩ ﻟﻮﮒ؟</text>
+ <text x="230" y="150" xml:lang="en">Urdu (IN)</text>
+ </g>
+ <g systemLanguage="ur-PK">
+ <text x="20" y="220" xml:lang="ur-PK" font-family=" Tahoma,'MS Farsi','Arial Unicode MS'" font-size="19">ﻦﻴﻫ ﻰﺘﻠﻭﺒ ﻦﻴﻬﻨ ﻦﻭﻴﻜ ﻮﺪﺭﺃ بس ﻮﻩ ﻟﻮﮒ؟</text>
+ <text x="230" y="150" xml:lang="en">Urdu (PK)</text>
+ </g>
+ <!-- should have a generic Urdu here for when user preference is Urdu but neither Pakistan Urdu nor Indian Urdu -->
+ <g systemLanguage="uz">
+ <text x="20" y="220" xml:lang="uz" font-size="22">Nega ular uzbek tilinda gapirmaidilar?</text>
+ <text x="230" y="150" xml:lang="en">Uzbek</text>
+ </g>
+ <g systemLanguage="vi">
+ <text x="20" y="220" xml:lang="vi" font-family="Tahoma,Verdana,'Verdana Ref','Arial Unicode MS'" font-size="22">Tại sao họ không thể chỉ nói tiếng Việt ?</text>
+ <text x="230" y="150" xml:lang="en">Vietnamese</text>
+ </g>
+ <g systemLanguage="yi">
+ <text x="20" y="220" xml:lang="yi" font-family="Tahoma,'Arial Unicode MS'" font-size="22">פֿאַרװאָס רעדט מען ניט פּשוט ייִדיש ?</text>
+ <text x="230" y="150" xml:lang="en">Yiddish</text>
+ </g>
+ <g systemLanguage="zh-CN">
+ <text x="20" y="220" font-family="'MS Hei','MS Song',LiSu,隶书,Code2000,'Arial Unicode MS'" font-size="26" xml:lang="zh-CN">他们为什么不说中文 (中国) ?</text>
+ <text x="230" y="150" xml:lang="en">Chinese (CN)</text>
+ </g>
+ <g systemLanguage="zh-TW">
+ <text x="20" y="220" xml:lang="zh-TW" font-family="MingLiU,細明體,PMingLiU,新細明體,DFP-SMTWSong,Code2000,'Arial Unicode MS'" font-size="26">他們爲什麽不說中文(台灣)?</text>
+ <text x="230" y="150" xml:lang="en">Chinese (TW)</text>
+ </g>
+ <g>
+ <!-- the default case, try three languages of W3C host institutions -->
+ <text x="90" y="100" fill="#700" font-size="14">You have no (matching) language preference set</text>
+ <text x="20" y="180" xml:lang="ja-JP" font-family="MS Gothic,MS ゴシック,MS Mincho,MS 明朝,Code2000,'Arial Unicode MS',DFP-SMTWSong" font-size="20">なぜ、みんな日本語を話してくれないのか?</text>
+ <text x="20" y="220" xml:lang="en-US">Why can't they just speak English ?</text>
+ <text x="20" y="260" xml:lang="fr-fR" font-size="16">Pourquoi, tout simplement, ne parlent-ils pas en Français ?</text>
+ </g>
+ </switch>
+ <!-- action item was to make a switch "for all ISO 639-1 language codes", a large task not completed. But there is enough here to make a good test case, including 19 of the top 20 langiuages by number of speakers (except Punjabi). Here is the full list (trailing * indicates language included in this test), accurate as of October 22, 2002 from the registration authority: http://lcweb.loc.gov/standards/iso639-2/langcodes.html aa Afar ab Abkhazian af Afrikaans * am Amharic * ar Arabic * as Assamese ae Avestan ay Aymara az Azerbaijani ba Bashkir be Byelorussian bg Bulgarian * bh Bihari bi Bislama bn Bengali [Bangla] * bo Tibetan * br Breton bs Bosnian ca Catalan * ce Chechen ch Chamorro co Corsican cs Czech * cu Church Slavic cv Chuvash cy Welsh * da Danish * de German * dz Dzongkha [Bhutani] el Greek, Modern (1453-) * en English, Modern * eo Esperanto es Spanish * et Estonian eu Basque * fa Persian (Farsi) * fi Finnish * fj Fijian fo Faeroese fr French, Modern * fy Frisian ga Irish gd Scots Gaelic * gl Gallegan [Galician] gn Guarani gu Gujarati * gv Manx ha Hausa he Hebrew * hi Hindi * ho Hiri Motu hr Croatian * hu Hungarian * hy Armenian * hz Herero ia Interlingua id Indonesian * ie Interlingue ik Inupiak is Icelandic * it Italian * iu Inuktitut * iw Hebrew * ja Japanese * jw Javanese ka Georgian * ki Kikuyu kj Kuanyama kk Kazakh * kl Kalaallisut [Greenlandic] km Khmer [Cambodian] kn Kannada * ko Korean * ks Kashmiri ku Kurdish kv Komi kw Cornish ky Kirghiz * la Latin ln Lingala lo Lao [Laothian] lt Lithuanian * lv Latvian [Lettish] mg Malagasy mh Marshall mi Maori mk Macedonian * ml Malayalam mn Mongolian mo Moldavian mr Marathi * ms Malay mt Maltese my Burmese na Nauru nb Norwegian Bokmal nd Ndebele, North ne Nepali ng Ndonga nl Dutch * nn Norwegian Nynorsk no Norwegian * nr Ndebele, South nv Navajo ny Chichewa~@Nyanja oc Occitan (post 1500); Provencal om Oromo [Afan] or Oriya * os Ossetian; Ossetic pa Panjabi pi Pali pl Polish * ps Pushto [Pashto] pt Portuguese * qu Quechua rm Rhaeto-Romance rn Kirundi ro Romanian * ru Russian * rw Kinyarwanda sa Sanskrit * sc Sardinian sd Sindhi se Northern Sami sg Sangro sr Serbian * si Sinhalese * sk Slovak sl Slovenian * sm Samoan sn Shona so Somali sq Albanian * sr Serbian ss Swati [Siswati] st Sotho, Southern [Sesotho] su Sundanese sv Swedish * sw Swahili ta Tamil * te Tegulu * tg Tajik * th Thai * ti Tigrinya tk Turkmen tl Tagalog * tn Tswana [Setswana] to Tonga tr Turkish * ts Tsonga tt Tatar * tw Twi ug Uighur uk Ukrainian * ur Urdu * uz Uzbek * vi Vietnamese * vo Volapuk wo Wolof xh Xhosa yi Yiddish * yo Yoruba za Zhuang zh Chinese * zu Zulu note: http://msdn.microsoft.com/workshop/management/ISO639codes.htm is obselete and incorrect -->
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-03-t.svg
new file mode 100644
index 0000000000..b03faee540
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-03-t.svg
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN" owner="CL" desc="Tests the switch element with requiredFeature" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: struct-cond-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Tests the &lt;switch&gt; element with requiredFeature. If a red rectangle with white text 'FAIL' is
+ displayed, the test fails. Otherwise, if a green rectangle is displayed in the lower part with the text '',
+ the test is passed.
+ </p>
+ <p>
+ The red rectangle and the white text each require a non-existent feature; the test attribute will thus
+ evaluate to false and neither element will be rendered by a compliant implementation.
+ </p>
+ <p>
+ The upper subtest is informative; it distinguishes between a purely SVG Tiny 1.2
+ implementation and others which also implement more (eg SVG Full 1.1, or
+ some profile of SVG 1.2 greater than Tiny). The results of this subtest
+ does not affect the pass/fail criteria.
+ </p>
+ <p>
+ Because SVG Tiny does not support for SVG Full DOM, an SVG Tiny implementation which
+ does not support other SVG Profiles should show a rectangle
+ <span style="background: rgb( 95, 158, 160)">like this</span>.
+ If the application supports the DOM, meaning that it does more than just SVG Tiny, it
+ should show a rectangle <span style="background: rgb( 32, 178, 170)">like this</span>.
+ Either result is a pass.
+ </p>
+ <p>
+ The lower subtest,has another switch. The first child has a requiredFeature
+ set to http://www.w3.org/TR/SVG11/feature#BasicText which all SVG Tiny implementations
+ must support. If the application does, the lower rectangle is displayed in green
+ <span style="background:green; color: white">like this</span>. Otherwise, a red rectangle
+ indicates that the text has failed.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-cond-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <switch>
+ <g requiredFeatures="http://www.w3.org/TR/SVG11/feature#SVGDOM">
+ <rect x="30" y="20" width="420" height="130" fill="rgb( 32, 178, 170)" />
+ <text x="240" y="100" font-size="18" text-anchor="middle">This viewer does more than SVG Tiny 1.2</text>
+ </g>
+ <g>
+ <rect x="30" y="20" width="420" height="130" fill="rgb( 95, 158, 160)" />
+ <text x="240" y="100" font-size="18" text-anchor="middle">
+ This viewer
+ does not implement SVG Full DOM
+ </text>
+ </g>
+ </switch>
+ <switch transform="translate(0, 140)">
+ <g requiredFeatures="http://www.w3.org/TR/SVG11/feature#BasicText">
+ <rect x="30" y="20" width="420" height="130" fill="green" />
+ <text x="240" y="100" font-size="18" text-anchor="middle" fill="white">SVG Basic Text feature supported</text>
+ </g>
+ <g>
+ <rect x="30" y="20" width="420" height="130" fill="red" />
+ <text x="240" y="100" font-size="18" text-anchor="middle" fill="white">Fail: Basic Text feature not supported</text>
+ </g>
+ </switch>
+
+ <rect x="30" y="20" width="420" height="270" fill="red" requiredFeatures="http://example.org/NotAFeature"/>
+ <text x="240" y="180" fill="white" text-anchor="middle" font-size="36"
+ requiredFeatures="http://www.w3.org/TR/SVG11/feature#NotAFeatureEither">FAIL</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-204-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-204-t.svg
new file mode 100644
index 0000000000..be7c309109
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-204-t.svg
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="AE" desc="Required Formats Attribute" status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: struct-cond-204-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Required Formats Attribute</p>
+ <p>
+ A series of switches are used to determine which Internet Media types ('MIME types')
+ are supported, using the 'requiredFormats' attribute,
+ displaying a 'yes' or 'no' as appropriate. The test is passed if there is text in
+ the second row of each column, and that text is only
+ <span style="color:#070">green</span> (in the top table)
+ or <span style="color:rgb(138, 43, 226)">blueviolet</span> (in the bottom table);
+ no <span style="color:red">red</span> text is displayed.
+ </p>
+ <p>
+ The SVG Tiny 1.2 specification mandates certain formats, so these must be supported:
+ image/jpeg, image/png, image/svg+xml.
+ It is an error not to support them, therefore 'yes' is green and 'no' is red.
+ </p>
+ <p>
+ This test also checks for support of Internet Media types which are
+ assumed to not exist and are unlikely to ever be registered: garbage/garbage.
+ Therefore, 'yes' is red and 'no' is green.
+ </p>
+ <p>
+ Lastly, most media types are optional. For example, image/tiff may be
+ supported but support is not mandated by the SVG Tiny 1.2 specification.
+ The second table examines these optional formats.
+ Both 'yes' and 'no' are displayed in blueviolet. Whether the particular Internet Media type
+ is supported or not does not affect whether the test is passed or failed, but does provide useful
+ information about the optional capabilities of a particular implementation.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-cond-204-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g fill="#555" font-size="10" text-anchor="middle">
+ <text fill="#000" x="240" font-size="14" y="30" xml:id="display-title">requiredFormats Attribute</text>
+ <text x="240" y="45" xml:id="comment-1">
+ Supported Internet Media types are determined, using the 'requiredFormats' attribute
+ </text>
+ <!--text x="240" y="57" xml:id="comment-2">
+ Results that are expected are marked as such.
+ </text-->
+ </g>
+ <g font-size="10" transform="translate(-30,97)">
+ <text text-anchor="end" x="340" y="-15" fill="#555" font-size="14">Mandatory Formats</text>
+ <text x="350" y="-15" fill="#555" font-size="14">Supported?</text>
+ <text text-anchor="end" x="340" y="0" fill="black">image/svg+xml</text>
+ <switch>
+ <text x="350" y="0" fill="green" requiredFormats="image/svg+xml">Yes (required)</text>
+ <text x="350" y="0" fill="red">No (fail)</text>
+ </switch>
+ <text text-anchor="end" x="340" y="12" fill="black">image/png</text>
+ <switch>
+ <text x="350" y="12" fill="green" requiredFormats="image/png">Yes (required)</text>
+ <text x="350" y="12" fill="red">No (fail)</text>
+ </switch>
+ <text text-anchor="end" x="340" y="24" fill="black">image/jpeg</text>
+ <switch>
+ <text x="350" y="24" fill="green" requiredFormats="image/jpeg">Yes (required)</text>
+ <text x="350" y="24" fill="red">No (fail)</text>
+ </switch>
+ <text text-anchor="end" x="340" y="36" fill="black">foo/foo</text>
+ <switch>
+ <text x="350" y="36" fill="red" requiredFormats="garbage/garbage">Yes (fail)</text>
+ <text x="350" y="36" fill="green">No (expected)</text>
+ </switch>
+ <text text-anchor="end" x="340" y="48" fill="black">image/png image/svg+xml foo/foo</text>
+ <switch>
+ <text x="350" y="48" fill="red" requiredFormats="image/png image/svg+xml garbage/garbage">Yes (fail)</text>
+ <text x="350" y="48" fill="green">No (expected)</text>
+ </switch>
+ <text text-anchor="end" x="340" y="60" fill="black">image/svg+xml image/png image/jpeg</text>
+ <switch>
+ <text x="350" y="60" fill="green" requiredFormats="image/svg+xml image/png image/jpeg">Yes (required)</text>
+ <text x="350" y="60" fill="red">No (fail)</text>
+ </switch>
+
+ <text text-anchor="end" x="340" y="85" fill="#555" font-size="14">Optional Formats</text>
+ <text x="350" y="85" fill="#555" font-size="14">Supported?</text>
+
+ <text text-anchor="end" x="340" y="100" fill="black">image/tif</text>
+ <switch>
+ <text x="350" y="100" fill="rgb(138, 43, 226)" requiredFormats="image/tif">Yes</text>
+ <text x="350" y="100" fill="rgb(138, 43, 226)">No </text>
+ </switch>
+ <text text-anchor="end" x="340" y="112" fill="black">image/g3fax</text>
+ <switch>
+ <text x="350" y="112" fill="rgb(138, 43, 226)" requiredFormats="image/g3fax">Yes</text>
+ <text x="350" y="112" fill="rgb(138, 43, 226)">No</text>
+ </switch>
+
+ <text text-anchor="end" x="340" y="124" fill="black">video/mpeg</text>
+ <switch>
+ <text x="350" y="124" fill="rgb(138, 43, 226)" requiredFormats="video/mpeg">Yes</text>
+ <text x="350" y="124" fill="rgb(138, 43, 226)">No</text>
+ </switch>
+ <text text-anchor="end" x="340" y="136" fill="black">video/3gpp</text>
+ <switch>
+ <text x="350" y="136" fill="rgb(138, 43, 226)" requiredFormats="video/3gpp">Yes</text>
+ <text x="350" y="136" fill="rgb(138, 43, 226)">No</text>
+ </switch>
+
+ <text text-anchor="end" x="340" y="148" fill="black">audio/vnd.wave;codec=1</text>
+ <switch>
+ <text x="350" y="148" fill="rgb(138, 43, 226)" requiredFormats="audio/vnd.wave;codec=1">Yes</text>
+ <text x="350" y="148" fill="rgb(138, 43, 226)">No</text>
+ </switch>
+
+ <text text-anchor="end" x="340" y="160" fill="black">audio/3gpp</text>
+ <switch>
+ <text x="350" y="160" fill="rgb(138, 43, 226)" requiredFormats="audio/3gpp">Yes</text>
+ <text x="350" y="160" fill="rgb(138, 43, 226)">No</text>
+ </switch>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-209-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-209-t.svg
new file mode 100644
index 0000000000..babb480b15
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-209-t.svg
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CM" owner="DS" desc="Test to determine if 'display' or 'visibility' attributes have an incorrect effect on the 'switch' element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.3 $" testname="$RCSfile: struct-cond-209-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test evaluates the effects of the 'display' or 'visibility'
+ attributes on a switch statement. The result should be a green circle
+ in the center of the output window.
+ </p>
+ <p>
+ The rendered picture should match the reference image, except for
+ possible variations in the labelling text (per CSS2 rules). The pass
+ condition is seeing a green circle in the center of the image. If a
+ gray rectangle is visible, the test cannot be evaluated because the
+ 'display' attribute is not supported. If a blue rectangle is visible,
+ the test cannot be evaluated because the 'visibility' attribute is not
+ supported. If a red rectangle with a gray stroke is visible, the test
+ is failed because the switch is affected by the 'display' attribute.
+ If a red rectangle with a black stroke is visible, the test is failed
+ because the switch is affected by the 'display' attribute.
+ </p>
+ <p>
+ The test uses the 'rect' and 'circle' elements, as well as basic fill
+ (solid primary colors), stroke (black or gray 2-pixel lines), and the
+ 'display' and 'visibility' attributes.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-cond-209-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content">
+
+ <circle cx='240' cy='180' r='23' fill='lime' />
+
+ <switch xml:id="test-display">
+ <rect fill="gray" stroke-width="2" x="215" y="155" width="50" height="50" display="none" />
+ <rect fill="red" stroke="gray" stroke-width="2" x="215" y="155" width="50" height="50" />
+ </switch>
+
+ <switch xml:id="test-visibility">
+ <rect fill="blue" stroke-width="2" x="215" y="155" width="50" height="50" visibility="hidden" />
+ <rect fill="red" stroke="blue" stroke-width="2" x="215" y="155" width="50" height="50" />
+ </switch>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.3 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-210-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-210-t.svg
new file mode 100644
index 0000000000..dbda7b27f0
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-cond-210-t.svg
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CM" owner="DS" desc="Test to determine if referenced resource (elements or paint servers) are still displayed event if hidden by a 'switch' element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.3 $" testname="$RCSfile: struct-cond-210-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test evaluates the effects of the switch statement on referencing
+ content such as gradients or elements. The result should be a yellow
+ rectangle in the center of the output window, with green circles in
+ three of the corners of the rectangle.
+ </p>
+ <p>
+ The rendered picture should match the reference image, except for
+ possible variations in the labelling text (per CSS2 rules). The pass
+ condition is seeing three circles, one solid green circle in upper
+ right corner of the rectangle, and a circle with a green gradient in
+ each of the bottom corners of the rectangle. If a red or black circle
+ is visible in the upper left corner of the rectangle, the test cannot
+ be evaluated because the 'switch' is not correctly supported. If any of
+ the upper-right or lower circles is not visible, or does not have the
+ correct fill, the test is failed. If the bottom-right circle is not
+ visible or does not have the gradient fill, then the 'switch' is not
+ correctly supported, and does not allow one conditionally hidden
+ resource to reference another.
+ </p>
+ <p>
+ The test uses the 'rect', 'circle', 'gradient', and 'use' elements, as
+ well as basic fill (solid primary colors) and radial gradients.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-cond-210-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <switch>
+ <g>
+ <rect fill="yellow" x="120" y="90" width="240" height="180" />
+ </g>
+ <g fill="red">
+ <circle xml:id="ref-source" cx="150" cy="120" r="25" />
+
+ <radialGradient xml:id="ref-gradient">
+ <stop offset="0" stop-color="green" />
+ <stop offset="1" stop-color="lime" />
+ </radialGradient>
+ </g>
+ <g>
+ <circle xml:id="ref-source-gradient" cx="150" cy="240" r="25" fill="url(#ref-gradient)"/>
+ </g>
+ </switch>
+
+ <use xlink:href="#ref-source" x="180" fill="lime" />
+ <use xlink:href="#ref-source-gradient" x="180" />
+ <circle xml:id="ref-source" cx="150" cy="240" r="25" fill="url(#ref-gradient)"/>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.3 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-defs-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-defs-01-t.svg
new file mode 100644
index 0000000000..c2ffbfd0a3
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-defs-01-t.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="TT" desc="Test to determine if the defs element is used as a container correctly" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: struct-defs-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test to verify that the defs element is used as a container correctly.</p>
+ <p>In this test a fill is created which is solid red. The view should be a solid red rectangle centered in the viewport 100 pixels from from left,top and right,bottom. Also, in the defs sections there are rectangle defined, one to paint over the entire canvas with a green fill and the other to obscure most of the red rectangle. The green rectangles should not show in the view as defs are referenced items and are not rendered. No green should show.</p>
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ <p>The test uses the 'rect' element, as well as basic fill (solid primary colors), stroke (black 1-pixel lines), font-family (Arial) and font-size properties.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-defs-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs xml:id="references">
+ <rect xml:id="rect11" x="0" y="0" width="480" height="360" color="#008000" />
+ </defs>
+ <defs>
+ <rect x="160" y="100" width="160" height="160" fill="#008000" />
+ </defs>
+ <rect x="140" y="80" width="200" height="200" fill="#F00" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-defs-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-defs-201-t.svg
new file mode 100644
index 0000000000..e368331f89
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-defs-201-t.svg
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ED" desc="Tests display=none on the defs element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: struct-defs-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Tests that the value of the display property on the defs element or on its descendants
+ doesn't prevent the elements from being referenced.
+ </p>
+ <p>
+ The test has passed if the following conditions are met:
+ </p>
+ <ol>
+ <li>there are 8 big rects visible each of a different color.</li>
+ <li>on top of the 8 big rects there are 8 circles that contain the reference color, the color of each circle must match the color of the rect to the right of its center</li>
+ <li>from the top-left to the top-right corner the colors must be: green, lime, yellow, olive.</li>
+ <li>from the bottom-left to the bottom-right corner the colors must be: navy, teal, blue, fuchsia.</li>
+ </ol>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-defs-201-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <defs display="none">
+ <rect xml:id="r1" x="-50" y="-50" width="100" height="100" fill="currentColor"/>
+ <rect xml:id="r2" x="-50" y="-50" width="100" height="100" fill="currentColor" display="inline"/>
+ <rect xml:id="r3" x="-50" y="-50" width="100" height="100" fill="currentColor" display="none"/>
+ <g xml:id="g1" display="none">
+ <rect xml:id="r4" x="-50" y="-50" width="100" height="100" fill="currentColor"/>
+ <g xml:id="g2">
+ <use xml:id="u1" xlink:href="#r1" color="olive"/>
+ <use xml:id="u2" xlink:href="#r3" color="red"/>
+ <use xml:id="u3" xlink:href="#r1" transform="translate(-300 100)" color="navy"/>
+ <g xml:id="g3" display="none">
+ <use xml:id="u4" xlink:href="#r1" color="teal"/>
+ <use xml:id="u5" xlink:href="#r3" color="red" display="none"/>
+ <use xml:id="u6" xlink:href="#r1" transform="translate(100 0)" color="blue"/>
+ </g>
+ </g>
+ </g>
+ <use xml:id="u7" xlink:href="#r1"/>
+ </defs>
+
+ <g transform="translate(0 20)">
+ <use xlink:href="#r1" transform="translate(100 100)" color="green"/>
+
+ <!-- this should not be visible -->
+ <use xlink:href="#r3" transform="translate(100 100)" color="red"/>
+
+ <use xlink:href="#r2" transform="translate(200 100)" color="lime"/>
+ <use xlink:href="#r4" transform="translate(300 100)" color="yellow"/>
+
+ <!-- should show olive and navy rects -->
+ <use xlink:href="#g2" transform="translate(400 100)"/>
+
+ <use xlink:href="#u4" transform="translate(200 200)"/>
+ <use xlink:href="#u6" transform="translate(200 200)"/>
+ <use xlink:href="#u7" transform="translate(400 200)" color="fuchsia"/>
+
+ <!-- this should not be visible -->
+ <use xlink:href="#g3" transform="translate(200 200)" display="inline"/>
+
+ <circle cx="50" cy="50" r="25" fill="green"/>
+ <circle cx="150" cy="50" r="25" fill="lime"/>
+ <circle cx="250" cy="50" r="25" fill="yellow"/>
+ <circle cx="350" cy="50" r="25" fill="olive"/>
+ <circle cx="50" cy="250" r="25" fill="navy"/>
+ <circle cx="150" cy="250" r="25" fill="teal"/>
+ <circle cx="250" cy="250" r="25" fill="blue"/>
+ <circle cx="350" cy="250" r="25" fill="fuchsia"/>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-discard-205-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-discard-205-t.svg
new file mode 100644
index 0000000000..b43a483843
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-discard-205-t.svg
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ED" desc="Tests that discard elements are discarded." status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: struct-discard-205-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test tests that discard elements themselves are discarded after being activated.
+ </p>
+ <p>
+ The test has passed if after 3 seconds there are three green circles visible, and no red.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-discard-205-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="translate(30,20)">
+ <circle xml:id="c1" cx="150" cy="100" r="50" fill="green"/>
+ <rect xml:id="r1" x="100" y="50" width="100" height="100" fill="red"/>
+
+ <circle xml:id="c2" cx="260" cy="100" r="50" fill="green"/>
+ <rect xml:id="r2" x="210" y="50" width="100" height="100" fill="red"/>
+
+ <circle xml:id="c3" cx="205" cy="200" r="50" fill="green"/>
+
+ <discard xml:id="discard1" xlink:href="#r1" begin="1s"/>
+ <discard xml:id="discard2" xlink:href="#r2" begin="1s"/>
+ <discard xml:id="discard3" xlink:href="#unresolved" begin="1s"/>
+
+ <set xml:id="set" attributeName="display" to="inline" begin="2s" dur="1s" fill="freeze"/>
+
+ <handler xe:event="beginEvent" xe:observer="set">
+ var d1 = document.getElementById("discard1");
+ var d2 = document.getElementById("discard2");
+ var d3 = document.getElementById("discard3");
+
+ if(d1 || d2 || d3)
+ document.getElementById("c3").setAttribute("fill", "red");
+ </handler>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-discard-206-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-discard-206-t.svg
new file mode 100644
index 0000000000..825bdb426c
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-discard-206-t.svg
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ED" desc="Tests that discard elements can be discarded before activation." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: struct-discard-206-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Tests that discard elements can be discarded before activation.
+ </p>
+ <p>
+ The test has passed if after 3 seconds there is there are 4 green rects visible,
+ and nothing red.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-discard-206-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="translate(30,-30)">
+ <rect xml:id="r0" x="100" y="100" width="200" height="200" fill="red"/>
+ <rect xml:id="r1" x="100" y="100" width="100" height="100" fill="green"/>
+ <rect xml:id="r2" x="200" y="100" width="100" height="100" fill="green"/>
+ <rect xml:id="r3" x="100" y="200" width="100" height="100" fill="green"/>
+ <rect xml:id="r4" x="200" y="200" width="100" height="100" fill="green"/>
+ <rect xml:id="r5" x="100" y="100" width="200" height="200" fill="red"/>
+
+ <discard xml:id="discard1" xlink:href="#r1" begin="2s"/>
+ <discard xml:id="discard2" xlink:href="#r2" begin="2s"/>
+ <discard xml:id="discard3" xlink:href="#r3" begin="2s"/>
+ <discard xml:id="discard4" xlink:href="#r5"/>
+ <discard xml:id="discard5" xlink:href="#discard1" begin="1s"/>
+ <discard xml:id="discard6" xlink:href="#discard2" begin="0s"/>
+ <discard xml:id="discard7" xlink:href="#discard3"/>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-02-t.svg
new file mode 100644
index 0000000000..746d8618ef
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-02-t.svg
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN" owner="VH" desc="validates the use of the preserveAspectRatio" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: struct-frag-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test validates the use of the preserveAspectRatio attribute on the root svg element in an SVG Tiny document. In this document, preserveAspectRatio is set to none and the width and height of the document set to 100%.</p>
+ <p>The document's viewBox is defined to be 100 by 100 with an origin in (100, 100). The content is made of 2 red squares and 2 orange circles.</p>
+ <p>Because preserveAspectRatio is set to 'none', the content should appear distorted: squares show as rectangles and circles show as ellipses.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-frag-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <rect x="100" y="100" width="50" height="50" fill="rgb(220, 20, 60)" />
+ <rect x="150" y="150" width="50" height="50" fill="rgb(220, 20, 60)" />
+ <circle cx="125" cy="175" r="25" fill="rgb(255, 215, 0)" />
+ <circle cx="175" cy="125" r="25" fill="rgb(255, 215, 0)" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-03-t.svg
new file mode 100644
index 0000000000..c054acf2cb
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-03-t.svg
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN" owner="VH" desc="validates the use of the preserveAspectRatio" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: struct-frag-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test validates the use of the preserveAspectRatio attribute on the root svg element in an SVG Tiny document. In this document, preserveAspectRatio is set to 'xMidYMid meet' and the width and height of the document set to 100%.</p>
+ <p>The document's viewBox is defined to be 100 by 100 with an origin in (100, 100). The content is made of 2 red squares and 2 orange circles.</p>
+ <p>Because preserveAspectRatio is set to 'xMidYMid meet', the content should appear centered within the viewport: squares show as squares (and not rectangles) and circles show as circles (and not ellipses).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-frag-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <rect x="100" y="100" width="50" height="50" fill="rgb(220, 20, 60)" />
+ <rect x="150" y="150" width="50" height="50" fill="rgb(220, 20, 60)" />
+ <circle cx="125" cy="175" r="25" fill="rgb(255, 215, 0)" />
+ <circle cx="175" cy="125" r="25" fill="rgb(255, 215, 0)" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-04-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-04-t.svg
new file mode 100644
index 0000000000..a9a1c09cc0
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-04-t.svg
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN" owner="VH" desc="validates svg element with no viewbox" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: struct-frag-04-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test validates the operation of the svg element when there is no viewbox.</p>
+ <p>The document's size is 480 by 360 with an x/y origin in (1000, 1000). Because x/y are ignored on the root svg element, the x/y origin should have no effect on the drawing.</p>
+ <p>The document contains squares and circles between the (100,100) and (200, 200) coordinates. Changing the viewport size should have no effect on the placement or scale of the document's conten.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-frag-04-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <rect x="100" y="100" width="50" height="50" fill="rgb(220, 20, 60)" />
+ <rect x="150" y="150" width="50" height="50" fill="rgb(220, 20, 60)" />
+ <circle cx="125" cy="175" r="25" fill="rgb(255, 215, 0)" />
+ <circle cx="175" cy="125" r="25" fill="rgb(255, 215, 0)" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-05-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-05-t.svg
new file mode 100644
index 0000000000..e1079cb2db
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-05-t.svg
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN" owner="CL" desc="support for namespace prefixes" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: struct-frag-05-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This tests that XML Namespaces are correctly implemented, in that the tuple of local name and namespace URI, rather than the prefix, is important. The first subtest is a group where the namespace prefix 's' is bound to the SVG namespace and an 's:circle' is drawn in pale yellow. The same group declares the default namespace to be a non-SVG namespace; the blue circle element in that namespace must not be drawn.</p>
+ <p>The second subtest puts the namespace declarations on the elements themselves. The prefix 'toto' is bound to the SVG namespace and the XLink namespace is made the default namespace. Thus, the blue '&lt;toto:a href="uri"&gt;Valid&lt;/toto:a&gt;' is a valid link and must be traversable. Select this link, then go back to the test.</p>
+ <p>The third subtest has no prefix on the element name 'a' and uses the usual 'xlink:' prefix on the 'href' attribute. However, both the default namespace and the namespace bound to the 'xlink' prefix are dummy namespaces. Not only should the link not be traversable, it must not even display at all. If the text 'Invalid' is displayed, the test fails.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-frag-05-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g font-family="Arial,sans-serif">
+ <s:g xmlns:s="http://www.w3.org/2000/svg" xmlns="http://www.example.org/notsvg">
+ <s:circle cx="240" cy="180" r="130" fill="#FF6" />
+ <circle cx="240" cy="180" r="150" fill="#369" />
+ </s:g>
+ <text x="240" y="100" text-anchor="middle" font-size="40" fill="#369">
+ <toto:a dahut:href="../images/linkingToc-t.svg" xmlns:toto="http://www.w3.org/2000/svg" xmlns:dahut="http://www.w3.org/1999/xlink">Valid</toto:a>
+ </text>
+ <text x="240" y="250" text-anchor="middle" font-size="40" fill="#C33">
+ <a xlink:href="../images/linkingToc-t.svg" xmlns="http://example.org/notsvg" xmlns:xlink="http://example.org/notxlink">Invalid</a>
+ </text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-06-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-06-t.svg
new file mode 100644
index 0000000000..168c0b18da
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-frag-06-t.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="VH" desc="tests required XML features, such as entities and the internal DTD subset" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: struct-frag-06-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test adds testing of some basic XML features SVG User Agents should support.</p>
+ <p>First, the test checks support for the default entities amp, lt, gt, apos and quot. This is what the first line shows in gray.</p>
+ <p>Second, the test checks support for hexadecimal and decimal character entities, as shown in the second line, again in gray</p>
+ <p>Finally, the last line shows usage of an entity defined in the document's internal DTD subset. The same geometry (a path) is reused twice, once filled in gray and ones stroked in gray.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-frag-06-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="30" y="30">Default entities: amp, lt, gt, apos, quot: </text>
+ <text x="90" y="60" fill="gray">&amp;, &lt;, &gt;, ', "</text>
+ <text x="30" y="100">Character references:</text>
+ <text x="90" y="130" fill="gray"> A hexadecimal (&amp;#x41)= A</text>
+ <text x="90" y="160" fill="gray"> A decimal (&amp;#65)= A</text>
+ <text x="30" y="200">Entity references:</text>
+ <text x="105" y="228" text-anchor="middle">gray</text>
+ <g transform="translate(90, 235) scale(0.2)" fill="gray">
+ <path d="M60,0 l60,0 l60,60 l0,60 l-60,60 l-60,0 l-60,-60 l0,-60 z" />
+ </g>
+ <text x="205" y="228" text-anchor="middle">outlined</text>
+ <g transform="translate(190, 235) scale(0.2)" fill="none" stroke="gray" stroke-width="5">
+ <path d="M60,0 l60,0 l60,60 l0,60 l-60,60 l-60,0 l-60,-60 l0,-60 z" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-group-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-group-01-t.svg
new file mode 100644
index 0000000000..f1cc59cd7c
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-group-01-t.svg
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AS" owner="TT" desc="Test that the g element functions correctly as a container." status="accepted"
+ approved="yes"
+ version="$Revision: 1.9 $" testname="$RCSfile: struct-group-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The test checks to see that graphics elements (g) can be nested and that the like attributes can be passed to the children. All the g elements for this test are in the g element whose xml:id=allGs. The two red rectangles and the yellow are in the g labeled rects. The reds inherit a fill color the green rect has a fill specified and it should not be overwritten. The two yellow rectangles should inherit the fill color and the transform attribute, they should be yellow and rotated at -20 degrees. These two rectangles are in g "yellowNrotate", that g is nested inside g "gratuitiousG". The black rectangle in the upper right, has no attributes inherited from its parent. The focus is nesting of g elements and passing on of attributes.</p>
+ <p>The rendered picture should match the reference image, except for possible variations in the labelling text (per CSS2 rules).</p>
+ <p>The test uses the 'rect' element, as well as basic fill (solid primary colors), stroke (black 1-pixel lines), font-family (Arial) and font-size properties.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-group-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g xml:id="rects" fill="red">
+ <rect x="0" y="0" width="240" height="180" />
+ <rect x="60" y="45" width="120" height="90" fill="green" />
+ <rect x="240" y="180" width="240" height="180" />
+ </g>
+ <g xml:id="singleG">
+ <rect x="240" y="0" width="240" height="180" fill="black" />
+ </g>
+ <g xml:id="gratuitiousG">
+ <g xml:id="yellowNrotate" fill="yellow" transform="rotate(-20)">
+ <rect x="0" y="224" width="40" height="40" />
+ <rect x="0" y="280" width="40" height="40" />
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-group-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-group-03-t.svg
new file mode 100644
index 0000000000..7370c1ba88
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-group-03-t.svg
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN" owner="VH" desc="property inheritance" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: struct-group-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test validates that properties are inherited (or not, depending on their defintion), from a group to its children.</p>
+ <p>The two rows displayed in this test should be identical. In the top row, each property is set to the value 'inherit'. In the bottom row, which is the reference, each property is set to the value that should be inherited in the top row.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-group-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <rect xml:id="propertyCell" x="-5" y="-14" width="110" height="22" />
+ <rect xml:id="sampleCell" x="-5" y="-14" width="50" height="22" />
+ </defs>
+ <g xml:id="grid" transform="translate(70, 150) rotate(-90)" fill="none" stroke="black">
+ <use xlink:href="#propertyCell" />
+ <use xlink:href="#propertyCell" y="22" />
+ <use xlink:href="#propertyCell" y="44" />
+ <use xlink:href="#propertyCell" y="66" />
+ <use xlink:href="#propertyCell" y="88" />
+ <use xlink:href="#propertyCell" y="110" />
+ <use xlink:href="#propertyCell" y="132" />
+ <use xlink:href="#propertyCell" y="154" />
+ <use xlink:href="#propertyCell" y="176" />
+ <use xlink:href="#propertyCell" y="198" />
+ <use xlink:href="#propertyCell" y="220" />
+ <use xlink:href="#propertyCell" y="242" />
+ <use xlink:href="#propertyCell" y="264" />
+ <use xlink:href="#propertyCell" y="286" />
+ <use xlink:href="#propertyCell" y="308" />
+ <use xlink:href="#propertyCell" y="330" />
+ <use xlink:href="#propertyCell" y="352" />
+ <g transform="translate(-50, 0)">
+ <use xlink:href="#sampleCell" />
+ <use xlink:href="#sampleCell" y="22" />
+ <use xlink:href="#sampleCell" y="44" />
+ <use xlink:href="#sampleCell" y="66" />
+ <use xlink:href="#sampleCell" y="88" />
+ <use xlink:href="#sampleCell" y="110" />
+ <use xlink:href="#sampleCell" y="132" />
+ <use xlink:href="#sampleCell" y="154" />
+ <use xlink:href="#sampleCell" y="176" />
+ <use xlink:href="#sampleCell" y="198" />
+ <use xlink:href="#sampleCell" y="220" />
+ <use xlink:href="#sampleCell" y="242" />
+ <use xlink:href="#sampleCell" y="264" />
+ <use xlink:href="#sampleCell" y="286" />
+ <use xlink:href="#sampleCell" y="308" />
+ <use xlink:href="#sampleCell" y="330" />
+ <use xlink:href="#sampleCell" y="352" />
+ </g>
+ <g transform="translate(-100, 0)">
+ <use xlink:href="#sampleCell" />
+ <use xlink:href="#sampleCell" y="22" />
+ <use xlink:href="#sampleCell" y="44" />
+ <use xlink:href="#sampleCell" y="66" />
+ <use xlink:href="#sampleCell" y="88" />
+ <use xlink:href="#sampleCell" y="110" />
+ <use xlink:href="#sampleCell" y="132" />
+ <use xlink:href="#sampleCell" y="154" />
+ <use xlink:href="#sampleCell" y="176" />
+ <use xlink:href="#sampleCell" y="198" />
+ <use xlink:href="#sampleCell" y="220" />
+ <use xlink:href="#sampleCell" y="242" />
+ <use xlink:href="#sampleCell" y="264" />
+ <use xlink:href="#sampleCell" y="286" />
+ <use xlink:href="#sampleCell" y="308" />
+ <use xlink:href="#sampleCell" y="330" />
+ <use xlink:href="#sampleCell" y="352" />
+ </g>
+ </g>
+ <g xml:id="properties" transform="translate(70, 150) rotate(-90)">
+ <text>color</text>
+ <text y="22">display</text>
+ <text y="44">fill</text>
+ <text y="66">fill-rule</text>
+ <text y="88">stroke</text>
+ <text y="110">stroke-dasharray</text>
+ <text y="132">stroke-dashoffset</text>
+ <text y="154">stroke-linecap</text>
+ <text y="176">stroke-linejoin</text>
+ <text y="198">stroke-miterlimit</text>
+ <text y="220">stroke-width</text>
+ <text y="242">visibility</text>
+ <text y="264">font-family</text>
+ <text y="286">font-size</text>
+ <text y="308">font-style</text>
+ <text y="330">font-weight</text>
+ <text y="352">text-anchor</text>
+ </g>
+ <g xml:id="inheritGroup" transform="translate(56, 155)">
+ <g color="#0F0">
+ <rect x="3" y="10" width="16" height="32" fill="currentColor" />
+ </g>
+ <g display="none" transform="translate(22, 0)">
+ <rect x="3" y="10" width="16" height="32" display="inherit" />
+ </g>
+ <g fill="#0F0" transform="translate(44, 0)">
+ <rect x="3" y="10" width="16" height="32" fill="inherit" />
+ </g>
+ <g fill-rule="evenodd" transform="translate(66, 0)">
+ <polygon points="10.5,0 21,21 0,7 21,7 0,21" fill-rule="inherit" fill="#0F0" transform="translate(3, 15) scale(0.7)" />
+ </g>
+ <g stroke="#0F0" transform="translate(88, 0)">
+ <rect x="3" y="10" width="16" height="32" stroke="inherit" fill="none" />
+ </g>
+ <g stroke-dasharray="2 2 5 5" transform="translate(110, 0)">
+ <line x1="11" y1="5" x2="11" y2="40" stroke="#0F0" stroke-dasharray="inherit" stroke-width="2" />
+ </g>
+ <g stroke-dashoffset="4" transform="translate(132, 0)">
+ <line x1="11" y1="5" x2="11" y2="40" stroke="#0F0" stroke-dashoffset="inherit" stroke-dasharray="2 2 5 5" stroke-width="2" />
+ </g>
+ <g stroke-linecap="round" transform="translate(154, 0)">
+ <line x1="11" y1="10" x2="11" y2="40" stroke="#0F0" stroke-linecap="inherit" stroke-width="10" />
+ </g>
+ <g stroke-linejoin="round" transform="translate(176, 0)">
+ <polyline points="3,40 11,10 19,40" stroke="#0F0" stroke-linejoin="inherit" stroke-width="5" fill="none" />
+ </g>
+ <g stroke-miterlimit="1" transform="translate(198, 0)">
+ <polyline points="3,40 11,10 19,40" stroke="#0F0" stroke-miterlimit="inherit" stroke-width="5" fill="none" />
+ </g>
+ <g stroke-width="5" transform="translate(220, 0)">
+ <line x1="11" y1="10" x2="11" y2="40" stroke="#0F0" stroke-width="inherit" />
+ </g>
+ <g visibility="hidden" transform="translate(242, 0)">
+ <line x1="11" y1="10" x2="11" y2="40" stroke="#0F0" visibility="inherit" />
+ </g>
+ <g font-family="serif" transform="translate(264, 0)">
+ <text x="11" y="30" font-size="20" text-anchor="middle" font-family="inherit">A</text>
+ </g>
+ <g font-size="10" transform="translate(286, 0)">
+ <text x="11" y="30" font-size="inherit" text-anchor="middle" font-family="serif">A</text>
+ </g>
+ <g font-style="italic" transform="translate(308, 0)">
+ <text x="11" y="30" font-style="inherit" text-anchor="middle" font-size="20" font-family="serif">A</text>
+ </g>
+ <g font-weight="bold" transform="translate(330, 0)">
+ <text x="11" y="30" font-weight="inherit" text-anchor="middle" font-family="serif" font-size="20">A</text>
+ </g>
+ <g text-anchor="middle" transform="translate(352, 0)">
+ <text x="11" y="30" text-anchor="inherit" font-family="serif" font-size="20">A</text>
+ </g>
+ </g>
+ <g xml:id="referenceGroup" transform="translate(56, 205)">
+ <g>
+ <rect x="3" y="10" width="16" height="32" fill="#0F0" />
+ </g>
+ <g transform="translate(22, 0)">
+ <rect x="3" y="10" width="16" height="32" display="none" />
+ </g>
+ <g transform="translate(44, 0)">
+ <rect x="3" y="10" width="16" height="32" fill="#0F0" />
+ </g>
+ <g transform="translate(66, 0)">
+ <polygon points="10.5,0 21,21 0,7 21,7 0,21" fill-rule="evenodd" fill="#0F0" transform="translate(3, 15) scale(0.7)" />
+ </g>
+ <g transform="translate(88, 0)">
+ <rect x="3" y="10" width="16" height="32" stroke="#0F0" fill="none" />
+ </g>
+ <g stroke-dasharray="2 2 5 5" transform="translate(110, 0)">
+ <line x1="11" y1="5" x2="11" y2="40" stroke="#0F0" stroke-dasharray="inherit" stroke-width="2" />
+ </g>
+ <g transform="translate(132, 0)">
+ <line x1="11" y1="5" x2="11" y2="40" stroke="#0F0" stroke-dashoffset="4" stroke-dasharray="2 2 5 5" stroke-width="2" />
+ </g>
+ <g transform="translate(154, 0)">
+ <line x1="11" y1="10" x2="11" y2="40" stroke="#0F0" stroke-linecap="round" stroke-width="10" />
+ </g>
+ <g transform="translate(176, 0)">
+ <polyline points="3,40 11,10 19,40" stroke="#0F0" stroke-linejoin="round" stroke-width="5" fill="none" />
+ </g>
+ <g transform="translate(198, 0)">
+ <polyline points="3,40 11,10 19,40" stroke="#0F0" stroke-miterlimit="1" stroke-width="5" fill="none" />
+ </g>
+ <g transform="translate(220, 0)">
+ <line x1="11" y1="10" x2="11" y2="40" stroke="#0F0" stroke-width="5" />
+ </g>
+ <g transform="translate(242, 0)">
+ <line x1="11" y1="10" x2="11" y2="40" stroke="#0F0" visibility="hidden" />
+ </g>
+ <g transform="translate(264, 0)">
+ <text x="11" y="30" font-size="20" text-anchor="middle" font-family="serif">A</text>
+ </g>
+ <g transform="translate(286, 0)">
+ <text x="11" y="30" font-size="10" text-anchor="middle" font-family="serif">A</text>
+ </g>
+ <g transform="translate(308, 0)">
+ <text x="11" y="30" font-style="italic" text-anchor="middle" font-size="20" font-family="serif">A</text>
+ </g>
+ <g transform="translate(330, 0)">
+ <text x="11" y="30" font-weight="bold" text-anchor="middle" font-family="serif" font-size="20">A</text>
+ </g>
+ <g transform="translate(352, 0)">
+ <text x="11" y="30" text-anchor="middle" font-family="serif" font-size="20">A</text>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-201-t.svg
new file mode 100644
index 0000000000..86ebf33d66
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-201-t.svg
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ snapshotTime="3"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ASl" desc="Tests that the snapshotTime attribute is set" status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: struct-svg-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ The svg should look the same on both sides and the text
+ should read "OK".
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-svg-201-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+
+ <rect xml:id="referenceframe" x="10" y="30" width="220" height="280" stroke="#000000" fill="none"/>
+ <rect xml:id="testframe" x="249" y="30" width="220" height="280" stroke="#000000" fill="none"/>
+ <rect xml:id="textframe" x="340" y="315" width="120" height="40" stroke="#000000" fill="none"/>
+
+ <text xml:id="title" x="10" y="25" font-size="15">Get-FloatTrait(snapshotTime) on svg and check value</text>
+ <text xml:id="referencetext" x="75" y="50" font-size="20">reference</text>
+ <text xml:id="scripttext" x="325" y="50" font-size="20">scripted</text>
+ <g fill="black">
+ <text xml:id="status" x="350" y="350" font-size="40" fill="red">Error!</text>
+ </g>
+
+ <text xml:id="reftextelement" x="20" y="150" font-size="25" fill="#184bed">
+ l8 4 bed
+ </text>
+
+ <text xml:id="scripttextelement" x="259" y="150" fill="#184bed" font-size="25">
+ l8 4 bed
+ </text>
+
+ <defs>
+ <path xml:id="moon" fill="#eac900" d="M 0 0 C 50 20 50 80 0 100 C 30 80 30 20 0 0 z" transform="rotate(30)"/>
+ </defs>
+
+ <use xlink:href="#moon" x="90" y="200"/>
+ <use xlink:href="#moon" x="329" y="200"/>
+
+ <script type="application/ecmascript">
+ <![CDATA[
+ var text = document.getElementById("status");
+ var svg = document.getElementById("svg-root");
+ var fs = svg.getFloatTrait("snapshotTime");
+ if(fs == "3")
+ {
+ text.setTrait("#text", "OK!");
+ text.setTrait("fill", "inherit");
+ }
+ ]]>
+ </script>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-202-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-202-t.svg
new file mode 100644
index 0000000000..dd4127b237
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-202-t.svg
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ASl" desc="Tests the default value for attribute snapshotTime" status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: struct-svg-202-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ The svg shold look the same on both sides and the text
+ should read "OK".
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-svg-202-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <rect xml:id="referenceframe" x="10" y="30" width="220" height="280" stroke="#000000" fill="none"/>
+ <rect xml:id="testframe" x="249" y="30" width="220" height="280" stroke="#000000" fill="none"/>
+ <rect xml:id="textframe" x="340" y="315" width="120" height="40" stroke="#000000" fill="none"/>
+
+ <text xml:id="title" x="10" y="25" font-size="15">GetFloatTrait(snapshotTime) on svg where snapshotTime is default</text>
+ <text xml:id="referencetext" x="75" y="50" font-size="20">reference</text>
+ <text xml:id="scripttext" x="325" y="50" font-size="20">scripted</text>
+ <g fill="black">
+ <text xml:id="status" x="350" y="350" font-size="40" fill="red">Error!</text>
+ </g>
+
+ <text xml:id="reftextelement" x="20" y="150" font-size="25" fill="#184bed">
+ l8 4 bed
+ </text>
+
+ <text xml:id="scripttextelement" x="259" y="150" fill="#184bed" font-size="25">
+ l8 4 bed
+ </text>
+
+ <defs>
+ <path xml:id="moon" fill="#eac900" d="M 0 0 C 50 20 50 80 0 100 C 30 80 30 20 0 0 z" transform="rotate(30)"/>
+ </defs>
+
+ <use xlink:href="#moon" x="90" y="200"/>
+ <use xlink:href="#moon" x="329" y="200"/>
+
+
+ <script type="application/ecmascript">
+ <![CDATA[
+ var text = document.getElementById("status");
+ var svg = document.getElementById("svg-root");
+ var fs = svg.getFloatTrait("snapshotTime");
+ if(fs == "0")
+ {
+ text.setTrait("#text", "OK!");
+ text.setTrait("fill", "inherit");
+ }
+ ]]>
+ </script>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-203-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-203-t.svg
new file mode 100644
index 0000000000..b2f9516285
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-203-t.svg
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ED" desc="Test svg element in svg." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: struct-svg-203-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test tests that any &lt;svg&gt; elements that are encountered inside
+ an &lt;svg&gt; element are ignored, if the user agent supports SVG Tiny 1.2 only.
+ </p>
+ <p>
+ If the user agent can handle SVG 1.1 Basic or Full, then the test has passed
+ if only the string "This text should be visible if the viewer supports at least SVG 1.1 Basic."
+ is visible.
+ </p>
+ <p>
+ If the user agent supports only SVG 1.2 Tiny then the test has passed if
+ the svg element and it's contents have been ignored. Only the string
+ "This text should be visible if the viewer supports only SVG 1.2 Tiny." should
+ be visible.
+ </p>
+ <p>
+ If <em>both</em> strings are visible then the test has failed.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-svg-203-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <text x="240" y="250" text-anchor="middle" font-size="10">This text should be visible if the viewer supports only SVG 1.2 Tiny.</text>
+
+ <svg x="10" y="200" width="460" height="100" viewBox="0 0 400 100" overflow="visible">
+ <rect width="400" height="100" fill="white"/>
+ <text x="200" y="30" text-anchor="middle" font-size="10">This text should be visible if the viewer supports at least SVG 1.1 Basic.</text>
+ </svg>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-204-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-204-t.svg
new file mode 100644
index 0000000000..804120d35e
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-svg-204-t.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="-100" height="-1"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ED" desc="Test negative values for width and height on the svg element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: struct-svg-204-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test is passed if nothing is rendered as the SVG root element
+ contains negative values for the width and height.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-svg-204-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <text x="240" y="150" text-anchor="middle">Failed</text>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-01-t.svg
new file mode 100644
index 0000000000..ee7dac8b44
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-01-t.svg
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN" owner="VH" desc="Tests that the viewer can handle various types of use references" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: struct-use-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The purpose of this test is to validate proper handling of the use element. In particular, the test checks the proper inheritance of properties through the shadow tree (rather than through the document tree).</p>
+ <p>The test should display various elements in different shades of green. If an element is not displayed in green, but in red fill and/or yellow stroke, then it is in error.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <g fill="red" stroke="yellow" stroke-width="3">
+ <rect xml:id="usedRect" width="20" height="20" />
+ <circle xml:id="usedCircle" cx="10" cy="10" r="10" />
+ <ellipse xml:id="usedEllipse" cx="10" cy="10" rx="10" ry="10" />
+ <line xml:id="usedLine" x1="0" y1="10" x2="20" y2="10" />
+ <path xml:id="usedPath" d="M 0 0 L 20 0 L 20 20 L 0 20 Z" />
+ <polygon xml:id="usedPolygon" points="0,0 20,0 20,20 0,20 0 0" />
+ <polyline xml:id="usedPolyline" points="0,0 20,0 20,20" />
+ <g xml:id="usedG">
+ <rect width="10" height="20" />
+ <rect x="10" width="10" height="20" fill="rgb(0,128,0)" />
+ </g>
+ <use xml:id="usedUse" xlink:href="#usedRect" />
+ <image xml:id="usedImage" xlink:href="../images/20x20.png" width="20" height="20" />
+ <text xml:id="usedText">Text</text>
+ </g>
+ </defs>
+ <g>
+ <g xml:id="labels" transform="translate(130, 40)" font-size="20" text-anchor="end">
+ <text>&lt;rect&gt;</text>
+ <text y="30">&lt;circle&gt;</text>
+ <text y="60">&lt;ellipse&gt;</text>
+ <text y="90">&lt;line&gt;</text>
+ <text y="120">&lt;polyline&gt;</text>
+ <text y="150">&lt;polygon&gt;</text>
+ <text y="180">&lt;path&gt;</text>
+ <text y="210">&lt;image&gt;</text>
+ <text y="240">&lt;text&gt;</text>
+ </g>
+ <g xml:id="labelsColumn2" transform="translate(310, 40)" font-size="20" text-anchor="end">
+ <text>&lt;g&gt;</text>
+ <text y="30">&lt;use&gt;</text>
+ </g>
+ </g>
+ <g transform="translate(150, 25)">
+ <use xlink:href="#usedRect" fill="#0F0" />
+ <use y="30" xlink:href="#usedCircle" fill="#0F0" />
+ <use y="60" xlink:href="#usedEllipse" fill="#0F0" />
+ <use y="90" xlink:href="#usedLine" stroke="#0F0" stroke-width="2" />
+ <use y="120" xlink:href="#usedPolyline" stroke="#0F0" stroke-width="2" fill="none" />
+ <use y="150" xlink:href="#usedPolygon" fill="#0F0" />
+ <use y="180" xlink:href="#usedPath" fill="#0F0" />
+ <use y="210" xlink:href="#usedImage" fill="#FF0" />
+ <use y="260" xlink:href="#usedText" fill="#0F0" font-weight="bold" font-size="25" font-style="italic" />
+ <use x="180" y="0" xlink:href="#usedG" fill="#0F0" />
+ <use x="180" y="30" xlink:href="#usedUse" fill="#0c0" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-03-t.svg
new file mode 100644
index 0000000000..c68cf8f321
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-03-t.svg
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CN" owner="VH" desc="tests x/y attribs on use element" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: struct-use-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The purpose of this test is to validate proper handling of the x/y attributes on the use element.</p>
+ <p>The test shows a &lt;use&gt; element displayed on the right. On the left, a group built as described in section 5.6 of the SVG 1.1 specification validates that the &lt;use element is properly processed.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <rect xml:id="usedRect" width="100" height="100" fill="rgb(250,220,0)" stroke="rgb(200,40,40)" stroke-width="20" />
+ </defs>
+ <text x="120" y="60" text-anchor="middle">Reference</text>
+ <text x="360" y="60" text-anchor="middle">&lt;use&gt;</text>
+ <!-- This group is constructed as described in section 5.6 of the -->
+ <!-- SVG 1.1 Specification. -->
+ <g xml:id="reference" transform="rotate(45,120,170) translate(70,120)">
+ <rect width="100" height="100" fill="rgb(250,220,0)" stroke="rgb(200,40,40)" stroke-width="20" />
+ </g>
+ <g transform="translate(240, 0)">
+ <use xlink:href="#usedRect" x="70" y="120" transform="rotate(45,120,170)" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-09-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-09-t.svg
new file mode 100644
index 0000000000..4444575405
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-09-t.svg
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE, AG" owner="AN, DS" desc="Tests the use element in symbol definition" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: struct-use-09-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This tests a set of 'use' and 'rect' elements inside 'g' elements, with
+ each referencing the one before. For the test to pass, 5 nested
+ rectangles with a green stroke must be rendered, and no red rectangles
+ must be rendered.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-09-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content">
+ <!-- put all of the actual test here -->
+ <defs>
+ <g xml:id="rect1">
+ <rect x="-50" y="-50" width="100" height="100" fill="none" stroke="green" stroke-width="3" />
+ </g>
+ <g xml:id="rect2">
+ <use xlink:href="#rect1" />
+ <rect x="-55" y="-55" width="110" height="110" fill="none" stroke="green" stroke-width="3" />
+ </g>
+ <g xml:id="rect3">
+ <use xlink:href="#rect2" />
+ <rect x="-60" y="-60" width="120" height="120" fill="none" stroke="green" stroke-width="3" />
+ </g>
+ <g xml:id="rect4">
+ <use xlink:href="#rect3" />
+ <rect x="-65" y="-65" width="130" height="130" fill="none" stroke="green" stroke-width="3" />
+ </g>
+ <g xml:id="rects">
+ <use xlink:href="#rect4" />
+ <rect x="-70" y="-70" width="140" height="140" fill="none" stroke="green" stroke-width="3" />
+ </g>
+ </defs>
+
+ <g>
+ <rect x="190" y="130" width="100" height="100" fill="none" stroke="red" />
+ <rect x="185" y="125" width="110" height="110" fill="none" stroke="red" />
+ <rect x="180" y="120" width="120" height="120" fill="none" stroke="red" />
+ <rect x="175" y="115" width="130" height="130" fill="none" stroke="red" />
+ <rect x="170" y="110" width="140" height="140" fill="none" stroke="red" />
+ </g>
+
+ <use x="240" y="180" xlink:href="#rects" />
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-201-t.svg
new file mode 100644
index 0000000000..ed6b32215d
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-201-t.svg
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ED" desc="Test reference restrictions on the 'use' element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: struct-use-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test tests reference restrictions on the use element. Each of the 5 different
+ restrictions is tested.
+ </p>
+ <p>
+ A compliant SVG Tiny 1.2 user agent must treat each of the invalid IRI:s as if the xlink:href
+ attribute hadn't been specified, which is the same as disabling rendering of the use element
+ in question. Thus for the test to pass none of the content that the use elements try to reference
+ must be visible, the end result should be 5 empty (white) rects.
+ </p>
+ <p>
+ For a user agent that handles at least SVG 1.1 Basic the testcase has still passed if the referenced
+ content in the rect that is labelled "B" is visible since this is allowed for 1.1.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-201-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="240" y="50" text-anchor="middle">Test &lt;use&gt; reference restrictions</text>
+
+ <g>
+ <!-- this is an invalid IRI because it directly creates a circular dependency -->
+ <use xlink:href="#svg-root" x="20" y="105" width="80" height="80"/>
+ <rect x="15" y="100" width="90" height="120" fill="none" stroke="black"/>
+ <rect x="15" y="190" width="90" height="30" fill="none" stroke="black"/>
+ <text x="60" y="210" text-anchor="middle">A</text>
+ </g>
+ <g>
+ <!-- this is an invalid IRI because it references an svg fragment, however it may be visible if SVG 1.1 is supported -->
+ <use xlink:href="../images/resources.svg#svg-root" x="110" y="105" width="80" height="80"/>
+ <rect x="105" y="100" width="90" height="120" fill="none" stroke="black"/>
+ <rect x="105" y="190" width="90" height="30" fill="none" stroke="black"/>
+ <text x="150" y="210" text-anchor="middle">B</text>
+ </g>
+ <g>
+ <!-- this is an invalid IRI because it references an entire file -->
+ <use xlink:href="../images/resources.svg" x="200" y="105" width="80" height="80"/>
+ <rect x="195" y="100" width="90" height="120" fill="none" stroke="black"/>
+ <rect x="195" y="190" width="90" height="30" fill="none" stroke="black"/>
+ <text x="240" y="210" text-anchor="middle">C</text>
+ </g>
+ <g>
+ <!-- this is an invalid IRI because it references a media resource other than svg -->
+ <use xlink:href="../images/1pixelred.png" x="290" y="105" width="80" height="80"/>
+ <rect x="285" y="100" width="90" height="120" fill="none" stroke="black"/>
+ <rect x="285" y="190" width="90" height="30" fill="none" stroke="black"/>
+ <text x="330" y="210" text-anchor="middle">D</text>
+ </g>
+ <g>
+ <!-- this is an invalid IRI because data IRI:s are not allowed on 'use' -->
+ <use xlink:href="data:image/svg+xml;charset=utf-8,%3Crect%20width%3D%22100%22%20height%3D%22100%22%20fill%3D%22red%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%2F%3E"
+ x="380" y="105" width="80" height="80"/>
+ <rect x="375" y="100" width="90" height="120" fill="none" stroke="black"/>
+ <rect x="375" y="190" width="90" height="30" fill="none" stroke="black"/>
+ <text x="420" y="210" text-anchor="middle">E</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-202-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-202-t.svg
new file mode 100644
index 0000000000..414f292039
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-202-t.svg
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ED" desc="Test reference restriction B on the 'use' element." status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: struct-use-202-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test tests the reference restriction B on the use element.
+ </p>
+ <p>
+ A compliant SVG Tiny 1.2 user agent must treat each of the invalid IRI:s as if the xlink:href
+ attribute hadn't been specified, which is the same as disabling rendering of the use element
+ in question. Thus for the test to pass the content that the use element tries to reference
+ must be invisible, the end result should be an empty (white) rect.
+ </p>
+ <p>
+ For a user agent that handles at least SVG 1.1 Basic the testcase has still passed if the referenced
+ content in the rect that is labelled "B" is visible since this is allowed for 1.1.
+ If the script in the external resource is executed then the color of the rect will be green.
+ If not then the rect will be red.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-202-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="240" y="50" text-anchor="middle">Test &lt;use&gt; reference restriction B</text>
+
+ <g>
+ <!-- it's unclear if this is an invalid IRI, it references a fragment that has a script in it -->
+ <use xlink:href="../images/scriptresource.svg#g" x="110" y="105" width="80" height="80"/>
+ <rect x="105" y="100" width="90" height="120" fill="none" stroke="black"/>
+ <rect x="105" y="190" width="90" height="30" fill="none" stroke="black"/>
+ <text x="150" y="210" text-anchor="middle">B</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-203-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-203-t.svg
new file mode 100644
index 0000000000..f501c6a132
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-203-t.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL, AS" owner="BB" desc="Tests external references on the use element" status="accepted"
+ approved="yes"
+ version="$Revision: 1.2 $" testname="$RCSfile: struct-use-203-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The intent of the file is to determine if the UA supports references to external SVG fragments. To pass this test, the UA agent must display a total of 8 graphical primitives (2 rectangles, 2 circles, 2 ellipses and 2 triangles). For each object, the UA should display a semi transparent duplicate copy at an offset position. See referenced image.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-203-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g xml:id="ExtContent">
+ <use xlink:href="../images/svgRef12.svg#alpha" />
+ <use xlink:href="../images/svgRef12.svg#beta" />
+ <use xlink:href="../images/svgRef12.svg#gamma" />
+ <use xlink:href="../images/svgRef12.svg#delta" />
+ <use xlink:href="../images/svgRef12.svg#testContent" x="-5" y="5" fill-opacity="0.5" />
+ </g>
+ <text font-size="20" x="240" y="30" text-anchor="middle">External references on &lt;use&gt;</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.2 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-204-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-204-t.svg
new file mode 100644
index 0000000000..bcbfdb3279
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-204-t.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL, AS" owner="BB" desc="Tests external references on the use element" status="accepted"
+ approved="yes"
+ version="$Revision: 1.2 $" testname="$RCSfile: struct-use-204-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The intent of the file is to determine if the UA supports references to external SVG fragments. To pass this test, the UA agent must display a total of 8 graphical primitives (2 rectangles, 2 circles, 2 ellipses and 2 triangles). For each object, the UA should display a semi-transparent duplicate copy at an offset position. See referenced image.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-204-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g xml:id="ExtContent">
+ <use xlink:href="../images/svgRef12.svg#alpha" />
+ <use xlink:href="../images/svgRef12.svg#beta" />
+ <use xlink:href="../images/svgRef12.svg#gamma" />
+ <use xlink:href="../images/svgRef12.svg#delta" />
+ <use xlink:href="../images/svgRef12.svg#testContent" x="-5" y="5" fill-opacity="0.5" />
+ </g>
+ <text font-size="20" x="240" y="30" text-anchor="middle">External references on &lt;use&gt;</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.2 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-205-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-205-t.svg
new file mode 100644
index 0000000000..e185903c75
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-205-t.svg
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="ED" desc="Test SVGElementInstance and events" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: struct-use-205-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test checks some aspects of the SVGElementInstance with regards to events.
+ </p>
+ <p>
+ Four blue rects should be visible at first. To run the test each rect must be clicked a minimum of two times. Once
+ to run the basic test, and once to verify that the event handler was removed properly. The test has passed if after
+ clicking all the rects two times or more there are four green rects with the word "Passed" on them. If anything red
+ is visible or the text on any of the rects say "Failed" then the test has failed.
+ </p>
+ <p>
+ The top-left rect checks that correspondingUseElement and correspondingElement are returning the correct values, and
+ also that the currentTarget isn't the same as target here.
+ </p>
+ <p>
+ The top-right rect checks that events bubble the correct way when SVGElementInstance is involved. It's almost the same
+ as the first subtest, but uses another 'use' element.
+ </p>
+ <p>
+ The bottom-left rect doesn't use 'use' elements at all, it's to illustrate event bubbling in normal trees as compared
+ to SVGElementInstance trees.
+ </p>
+ <p>
+ The bottom-right rect uses nested 'use' elements. The event handler 'nestedhandler' should be executed first, and will
+ check some aspects of nested use elements. It will modify what it references, and that is checked in the 'h4' event
+ handler.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-205-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="240" y="50" text-anchor="middle">Test SVGElementInstance and events</text>
+
+ <defs>
+ <g xml:id="g">
+ <rect xml:id="r" width="100" height="100" rx="10"/>
+ <text xml:id="t" font-size="9" x="50" y="50" text-anchor="middle" pointer-events="none" fill="white">Click here</text>
+ </g>
+ <use xml:id="nesteduse" xlink:href="#g">
+ <handler xml:id="nestedhandler" xe:event="click">
+ var link = "#fail";
+ // The correspondingUseElement is always the outermost use element if use elements are nested
+ if(event.target.correspondingUseElement == document.getElementById("u3"))
+ {
+ // The currentTarget is the 'nesteduse' use element when this event is received,
+ // and the target is the element where the event originated
+ if(event.currentTarget.correspondingElement == document.getElementById("nesteduse"))
+ {
+ link = "#pass";
+ }
+ }
+ document.getElementById("nesteduse").setAttributeNS("http://www.w3.org/1999/xlink", "href", link);
+
+ // Remove the handler, so that clicking again does nothing
+ document.getElementById("nesteduse").removeChild(document.getElementById("nestedhandler"));
+ </handler>
+ </use>
+ <g xml:id="fail">
+ <rect xml:id="rf" width="100" height="100" fill="red" rx="10"/>
+ <text xml:id="tf" font-size="9" x="50" y="50" text-anchor="middle" pointer-events="none" fill="white">Failed</text>
+ </g>
+ <g xml:id="pass">
+ <rect xml:id="rp" width="100" height="100" fill="green" rx="10"/>
+ <text xml:id="tp" font-size="9" x="50" y="50" text-anchor="middle" pointer-events="none" fill="white">Passed</text>
+ </g>
+ </defs>
+
+ <g transform="translate(40,-20)" fill="blue">
+ <use xml:id="u1" xlink:href="#g" x="100" y="100">
+ <handler xml:id="h1" xe:event="click">
+ var link = "#fail";
+ // The currentTarget is this use element, and the target should be the rect element where
+ // the event originated. Checks these conditions.
+ // if(event.target != event.currentTarget)
+ {
+ if(event.target.correspondingUseElement == event.currentTarget)
+ {
+ if(event.target.correspondingElement == document.getElementById("r"))
+ {
+ link = "#pass";
+ }
+ }
+ }
+ document.getElementById("u1").setAttributeNS("http://www.w3.org/1999/xlink", "href", link);
+
+ // Remove the handler, so that clicking again does nothing
+ document.getElementById("u1").removeChild(document.getElementById("h1"));
+ </handler>
+ </use>
+ <use xml:id="u2" xlink:href="#g" x="204" y="100">
+ <handler xml:id="h2" xe:event="click">
+ var link = "#fail";
+ // The target element should have a correspondingUseElement that is the element using it.
+ // In this case it should be 'u2', and the correspondingElement should be the rect with id 'r'.
+ if(event.target.correspondingUseElement == document.getElementById("u2"))
+ {
+ if(event.target.correspondingElement == document.getElementById("r"))
+ {
+ link = "#pass";
+ }
+ }
+ document.getElementById("u2").setAttributeNS("http://www.w3.org/1999/xlink", "href", link);
+
+ // Remove the handler, so that clicking again does nothing
+ document.getElementById("u2").removeChild(document.getElementById("h2"));
+ </handler>
+ </use>
+ <g xml:id="g3" transform="translate(100,204)">
+ <rect xml:id="r3" width="100" height="100" rx="10"/>
+ <text xml:id="t3" font-size="9" x="50" y="50" text-anchor="middle" pointer-events="none" fill="white">Click here</text>
+
+ <handler xml:id="h3" xe:event="click">
+ var status = "Failed";
+ // This subtest is included to show the how target and currentTarget works on normal elements.
+ if(event.target != event.currentTarget)
+ {
+ if(event.target == document.getElementById("r3"))
+ {
+ if(event.currentTarget == document.getElementById("g3"))
+ {
+ status = "Passed";
+ }
+ }
+ }
+ document.getElementById("r3").setAttributeNS(null, "fill", status == "Passed" ? "green" : "red");
+ document.getElementById("t3").textContent = status;
+
+ // Remove the handler, so that clicking again does nothing
+ document.getElementById("g3").removeChild(document.getElementById("h3"));
+ </handler>
+ </g>
+ <use xml:id="u3" xlink:href="#nesteduse" x="204" y="204">
+ <handler xml:id="h4" xe:event="click">
+ var link = "#fail";
+ // If the nested use handler was executed then the rect element where the event originated has no
+ // corresponding use element anymore, correspondingUseElement will be null.
+ if(!event.target.correspondingUseElement)
+ {
+ if(event.target.correspondingElement == document.getElementById("r"))
+ {
+ link = "#pass";
+ }
+ }
+ document.getElementById("u3").setAttributeNS("http://www.w3.org/1999/xlink", "href", link);
+
+ // Remove the handler, so that clicking again does nothing
+ document.getElementById("u3").removeChild(document.getElementById("h4"));
+ </handler>
+ </use>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-206-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-206-t.svg
new file mode 100644
index 0000000000..de8695755c
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-206-t.svg
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AS" owner="ED" desc="Tests interaction in use element" status="accepted"
+ approved="yes"
+ version="$Revision: 1.1 $" testname="$RCSfile: struct-use-206-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ If the user agent supports referencing external content you should see three green rects.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-206-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <use xml:id="use-elm" x="60" y="50" xlink:href="../images/struct-use-206-resource.svg#svg-root"/>
+ <rect x="300" y="170" width="120" height="120" fill="lime" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.1 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--
+ <g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-207-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-207-t.svg
new file mode 100644
index 0000000000..48952d0418
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-207-t.svg
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="AG" desc="Tests external references and computed inherited values" status="accepted"
+ approved="yes"
+ version="$Revision: 1.2 $" testname="$RCSfile: struct-use-207-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This file is intented to test the computed values in external
+ references. Both files (referencing and referenced) define similar
+ colors/gradients via 'color', 'linearGradient' and 'radialGradient'.
+ The ids of those definitions are the same but the actual appearance are
+ different. These definitions are used to test the property inheritance
+ feature of SVG.
+ </p>
+ <p>
+ The top left rectangle should be filled with the blue linear gradient
+ since the 'use' has a specified value defined in the 'defs' section.
+ The top right rectangle is forestgreen since the 'use' has a computed
+ value. The bottom left rectangle is also forestgreen since the fill is
+ not inherited from the referenced element's original parent. The bottom
+ right rectangle is filled with the orange radial gradient since the
+ computed value is given by the CSS cascade.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-207-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <linearGradient xml:id="linearGrad1" gradientUnits="objectBoundingBox" y1="0" x1="0" y2="1" x2="1">
+ <stop offset="0" stop-color="blue" />
+ <stop offset="0.33" stop-color="white" />
+ <stop offset="0.5" stop-color="navy" />
+ <stop offset="0.66" stop-color="white" />
+ <stop offset="1.0" stop-color="blue" />
+ </linearGradient>
+ <radialGradient xml:id="radialGrad1" gradientUnits="objectBoundingBox" cx="0.5" cy="0.5" r="0.5">
+ <stop offset="0" stop-color="blue" />
+ <stop offset="0.33" stop-color="white" />
+ <stop offset="0.5" stop-color="navy" />
+ <stop offset="0.66" stop-color="white" />
+ <stop offset="1.0" stop-color="blue" />
+ </radialGradient>
+ </defs>
+ <g color="green">
+ <use xlink:href="../images/svgRef13.svg#rect1" fill="url(#linearGrad1)" />
+ <use xlink:href="../images/svgRef13.svg#rect2" fill="currentColor" />
+ <use xlink:href="../images/svgRef13.svg#rect3" />
+ <use xlink:href="../images/svgRef13.svg#rect4" />
+ <text font-size="24" x="240" y="35" text-anchor="middle">External references and computed values</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.2 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-208-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-208-t.svg
new file mode 100644
index 0000000000..1c2ee83ba2
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-208-t.svg
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="AG" desc="Tests interaction in use element" status="accepted"
+ approved="yes"
+ version="$Revision: 1.3 $" testname="$RCSfile: struct-use-208-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Tests the reference a group of shapes with the use element.
+ </p>
+ <p>
+ The test is passed if two green circles with a black border are
+ rendered.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-208-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g fill="red">
+ <g xml:id="ref_circle">
+ <circle cx="150" cy="100" r="60" stroke="black" stroke-width="3"/>
+ <circle cx="300" cy="100" r="60" stroke="black" stroke-width="3"/>
+ </g>
+ </g>
+
+ <use xml:id="use-elm" x="0" y="0" xlink:href="#ref_circle" fill="green"/>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.3 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-209-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-209-t.svg
new file mode 100644
index 0000000000..e011582d61
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-209-t.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="AG" desc="Tests cyclic references" status="accepted"
+ approved="yes"
+ version="$Revision: 1.2 $" testname="$RCSfile: struct-use-209-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Tests circular references.
+ </p>
+ <p>
+ For this test to pass the green text "This text should be visible." must
+ be rendered. It is not an error if graphics are visible in addition to
+ the green text. It is not a requirement that graphics be rendered in
+ addition to the green text.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-209-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g transform="translate(60,50)">
+ <use xml:id="use-elm-1" xlink:href="../images/struct-use-209-t-cycles.svg#svg-root"/>
+ <rect width="120" height="120" fill="none" stroke="black"/>
+ <text x="60" y="140" text-anchor="middle" font-size="14">'use' referencing 'svg' element</text>
+ </g>
+
+ <g transform="translate(300,50)">
+ <use xml:id="use-elm-2" xlink:href="../images/struct-use-209-t-cycles.svg#image"/>
+ <rect width="120" height="120" fill="none" stroke="black"/>
+ <text x="60" y="140" text-anchor="middle" font-size="14">'use' referencing 'image' element</text>
+ </g>
+
+ <text x="240" y="260" text-anchor="middle" fill="green" font-size="35">This text should be visible.</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.2 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-recursion-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-recursion-01-t.svg
new file mode 100644
index 0000000000..6c0efd5143
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-recursion-01-t.svg
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="DS" desc="Test for recursion in 'use' elements." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: struct-use-recursion-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test checks for recursion in 'use' elements. The passing conditions are that the browser does not crash, and that at least one orange circle, and one yellow circle, and a line of green text are rendered.
+ Also, on an implementation-specific basis, additional orange and yellow circles with a dashed gray stroke may or may not be rendered, depending upon when and how the implementation detects the circular reference,
+ with the number of dashed circles of a given color indicating now many times the level of recurrsion permitted by the implementation.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-recursion-01-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <g xml:id="group-1">
+ <circle xml:id="circle-1" cx='100' cy='25' r='10' fill='#FF7F00' />
+ <use xml:id="use-1" x="0" y="25" xlink:href="#group-2" stroke="gray" stroke-width="2" stroke-dasharray="4" stroke-linecap="round"/>
+ </g>
+ <g xml:id="group-2">
+ <circle xml:id="circle-2" cx='380' cy='25' r='10' fill='#FFFF00' />
+ <use xml:id="use-2" x="0" y="25" xlink:href="#group-1" stroke="gray" stroke-width="2" stroke-dasharray="4" stroke-linecap="round"/>
+ </g>
+
+ <text xml:id="pass" x="240" y="280" text-anchor="middle" fill="green" font-size="24">This text should be visible.</text>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-recursion-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-recursion-02-t.svg
new file mode 100644
index 0000000000..f65fb8e58e
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-recursion-02-t.svg
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="DS" desc="Test for recursion in 'use' elements referencing external files." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: struct-use-recursion-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test checks for recursion in 'use' elements with external references. The passing conditions are that the browser does not crash, and that the green test is rendered. The passing conditions are that the
+ browser does not crash, and that at least one orange circle and a line of green text are rendered. Also, on an implementation-specific basis, additional orange and yellow circles with a dashed gray stroke may or may
+ not be rendered, depending upon when and how the implementation detects the circular reference, with the number of dashed circles of a given color indicating now many times the level of recurrsion permitted by the implementation..
+ </p>
+ <p>
+ This test depends upon 'struct-use-recursion-03-t.svg'.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-recursion-02-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <g xml:id="group-1">
+ <circle xml:id="circle-1" cx='100' cy='25' r='10' fill='#FF7F00' />
+ <use xml:id="use-1" x="0" y="25" xlink:href="struct-use-recursion-03-t.svg#group-2" stroke="gray" stroke-width="2" stroke-dasharray="4" stroke-linecap="round"/>
+ </g>
+
+ <text xml:id="pass" x="240" y="280" text-anchor="middle" fill="green" font-size="24">This text should be visible.</text>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-recursion-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-recursion-03-t.svg
new file mode 100644
index 0000000000..6cf57caa86
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/struct-use-recursion-03-t.svg
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="DS" desc="Test for recursion in 'use' elements referencing external files." status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: struct-use-recursion-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test checks for recursion in 'use' elements with external references. The passing conditions are that the browser does not crash, and that at least one yellow circle and a line of green text are rendered.
+ Also, on an implementation-specific basis, additional orange and yellow circles with a dashed gray stroke may or may not be rendered, depending upon when and how the implementation detects the circular reference,
+ with the number of dashed circles of a given color indicating now many times the level of recurrsion permitted by the implementation.
+ </p>
+ <p>
+ This test depends upon 'struct-use-recursion-02-t.svg'. It differs from 'struct-use-recursion-02-t.svg' in that the 'use' element comes before the 'circle' element.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: struct-use-recursion-03-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <g xml:id="group-2">
+ <use xml:id="use-2" x="0" y="25" xlink:href="struct-use-recursion-02-t.svg#group-1" stroke="gray" stroke-width="2" stroke-dasharray="4" stroke-linecap="round"/>
+ <circle xml:id="circle-2" cx='380' cy='25' r='10' fill='#FFFF00' />
+ </g>
+
+ <text xml:id="pass" x="240" y="280" text-anchor="middle" fill="green" font-size="24">This text should be visible.</text>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/styling-inherit-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/styling-inherit-01-t.svg
new file mode 100644
index 0000000000..9b15770eec
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/styling-inherit-01-t.svg
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE,AN" owner="CL" desc="Verify property inheritance" status="accepted"
+ approved="yes"
+ version="$Revision: 1.10 $" testname="$RCSfile: styling-inherit-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Verify property inheritance as required by 6.7 "Property inheritance". </p>
+ <p>For this test to pass:</p>
+ <p>At the center right, there is an ellipse. The fill color is not specified on that element but on its parent. The ellipse must be filled a solid yellow</p>
+ <p>At the top left, an oval shape is formed from a rectangle with a radial gradient. The color of the middle stop uses the keyword 'inherit' and thus takes its parent's value of green, giving a yellow, green, white gradient from the center to the edge.</p>
+ <p>At the bottom left, an oval shape is formed from a rectangle with a radial gradient. The color of the middle stop uses the value 'currentColor' and thus takes the value its parent's color property, a dark red, giving a yellow, dark red, white gradient from the center to the edge</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: styling-inherit-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g fill="yellow">
+ <g stroke="#555">
+ <ellipse rx="90" ry="60" cx="330" cy="140" />
+ </g>
+ </g>
+ <radialGradient xml:id="ygw" stop-color="green">
+ <stop offset="0%" stop-color="yellow" />
+ <stop offset="50%" stop-color="inherit" />
+ <stop offset="100%" stop-color="white" />
+ </radialGradient>
+ <rect width="180" height="120" x="40" y="20" stroke="none" fill="url(#ygw)" />
+ <radialGradient xml:id="yrw" color="#700">
+ <stop offset="0%" stop-color="yellow" />
+ <stop offset="50%" stop-color="currentColor" />
+ <stop offset="100%" stop-color="white" />
+ </radialGradient>
+ <rect width="180" height="120" x="40" y="160" stroke="none" fill="url(#yrw)" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/styling-pres-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/styling-pres-01-t.svg
new file mode 100644
index 0000000000..3fc2f57a40
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/styling-pres-01-t.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="CL" desc="Check !important in presentation attribute is an unsupported value" status="accepted"
+ approved="yes"
+ version="$Revision: 1.10 $" testname="$RCSfile: styling-pres-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Check that !important in presentation attribute is an unsupported attribute value. To pass, two rectangles should be drawn. A black filled rectangle and a lime green stroked rectangle.</p>
+ <p>
+ A fill attribute is set to red with !important. This is an unsupported attribute value,
+ consequently the fill attribute should be the lacuna value, which is black. Therefore, to pass, the rectangle should be filled with black.
+ </p>
+ <p>A lime green border is also drawn, to check that rendering continues after the element with the unsupported value.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: styling-pres-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <circle r="80" cx="240" cy="150" fill="blue" />
+ <rect width="200" height="160" x="140" y="70" fill="red !important" />
+ <rect width="200" height="160" x="140" y="70" fill="none" stroke="lime" stroke-width="4" />
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-01-t.svg
new file mode 100644
index 0000000000..8b345cdab2
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-01-t.svg
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="JF" desc="Test 'text-anchor' property (horizontal)." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: text-align-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test 'text-anchor' property (horizontal).</p>
+ <p>The three lines test the three values for property 'text-anchor': start, middle and end.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-align-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="34" x="5" y="40">Test 'text-anchor' (horizontal)</text>
+ <g xml:id="text-anchor" font-family="Arial" font-size="14">
+ <g transform="translate(230,130)">
+ <line stroke="black" x2="50" />
+ <circle r="3" />
+ <text font-size="30" fill="red">text-anchor:none</text>
+ </g>
+ <g transform="translate(230,180)">
+ <line stroke="black" x2="50" />
+ <circle r="3" />
+ <text font-size="30" text-anchor="start" fill="red">text-anchor:start</text>
+ </g>
+ <g transform="translate(230,230)">
+ <line stroke="black" x1="-25" x2="25" />
+ <circle r="3" />
+ <text font-size="30" text-anchor="middle" fill="green">text-anchor:middle</text>
+ </g>
+ <g transform="translate(230,280)">
+ <line stroke="black" x1="-50" x2="0" />
+ <circle r="3" />
+ <text font-size="30" text-anchor="end" fill="blue">text-anchor:end</text>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-07-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-07-t.svg
new file mode 100644
index 0000000000..14ebfe8a52
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-07-t.svg
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="CN" desc="Test horizontal baselines across script and font size changes." status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: text-align-07-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test horizontal baselines across script and font size changes.</p>
+ <p>
+ The dominant baseline should be alphabetic, so the 'ab' will be sitting
+ on the blue line, the japanese glyphs will be on the ideographic
+ baseline and '&#2339;' is a devangari character and will use the hanging
+ baseline. The smaller versions of the characters should be aligned to
+ the same baselines. So 'ab' on the blue line, the ideographic chars
+ slightly below the line and the devangari should be hanging from the
+ hanging baseline.
+ </p>
+ <p>Original test authored by Rodney Hardy at CISRA.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-align-07-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g font-family="'Arial Unicode MS',Georgia,'Times New Roman',Times,'MS Mincho',serif" font-size="30">
+ <!-- The dominant baseline should be alphabetic, so the 'ab' will be sitting on the blue line, the japanese glyphs will be on the ideographic baseline and '&#2339;' is a devangari character and will use the hanging baseline. The smaller versions of the characters should be aligned to the same baselines. So 'ab' on the blue line, the ideographic chars slightly below the line and the devangari should be hanging from the hanging baseline. -->
+ <text x="50" y="100" font-size="50">
+ a&#29340;&#2339;
+ <tspan font-size="25">a&#29340;&#2339;</tspan>
+ <tspan font-size="10">a&#29340;&#2339;</tspan>
+ </text>
+ <line x1="50" y1="100" x2="400" y2="100" stroke-width="1" stroke="blue" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-08-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-08-t.svg
new file mode 100644
index 0000000000..44447646d6
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-08-t.svg
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="CN" desc="Test horizontal baselines across script and font size changes (SVG Font)." status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: text-align-08-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test horizontal baselines across script and font size changes. It uses
+ an SVG Font, where the Latin letter "a" is a rectangle, the Japanese
+ letter "犜" is an upward-pointing triangle, and the Devanagari letter
+ "ण" is a downward-pointing triangle.
+ </p>
+ <p>
+ The dominant baseline should be alphabetic, so the 'a' will be sitting
+ on the alphabetic (blue) line, the japanese glyph (upward pointing
+ triangle) will be aligned on the ideographic (red) baseline and 'ण' is
+ a devangari character (downward pointing triangle) and will use the
+ hanging baseline (green). The smaller versions of the characters should
+ be aligned to the same baselines as the respective larger characters,
+ so all like shapes align to the same baseline..
+ </p>
+ <p>Original test authored by Rodney Hardy at CISRA.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-align-08-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font horiz-adv-x="500">
+ <font-face font-family="SVGFont" units-per-em="1000" ascent="800" descent="200" alphabetic="200" ideographic="0" hanging="900" />
+ <missing-glyph horiz-adv-x="500" d="M0 0L500 0L500 1000L0 1000M50 50L50 950L450 950L450 50Z" />
+ <glyph unicode=" " glyph-name="space" />
+ <glyph unicode="a" glyph-name="rectangle" d="M0 200L500 200L500 900L0 900Z" />
+ <glyph unicode="犜" glyph-name="upward-triangle" d="M0 0L500 0L250 900Z" />
+ <glyph unicode="ण" glyph-name="downward-triangle" d="M0 900L500 900L250 0Z" />
+ </font>
+ </defs>
+ <g font-family="SVGFont">
+ <!-- The dominant baseline should be alphabetic, so the 'ab' will be sitting on the blue line, the japanese glyphs will be on the ideographic baseline and '&#2339;' is a devangari character and will use the hanging baseline. The smaller versions of the characters should be aligned to the same baselines. So 'a' on the blue line, the ideographic chars slightly below the line and the devangari should be hanging from the hanging baseline. -->
+ <text x="50" y="200" font-size="150">
+ a犜ण
+ <tspan font-size="75">a犜ण</tspan>
+ <tspan font-size="30">a犜ण</tspan>
+ </text>
+ <line x1="50" y1="200" x2="433" y2="200" stroke-width="1" stroke="blue" />
+ <line x1="50" y1="230" x2="433" y2="230" stroke-width="1" stroke="red" />
+ <line x1="50" y1="95" x2="433" y2="95" stroke-width="1" stroke="green" />
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-201-t.svg
new file mode 100644
index 0000000000..33a60b08ed
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-201-t.svg
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="DS" desc="Test viewer basic capability to handle 'text-anchor' property." status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: text-align-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Test for viewer capability to handle the basics of the 'textAnchor'
+ alignment property for 'text' when it has child elements.
+ </p>
+ <p>
+ The first line from the top tests that a 'tspan' element is rendered
+ after the text content of the parent 'text' element.
+ </p>
+ <p>
+ The second line from the top tests that all the text content, including
+ that of child 'tspan' elements, is taken into account when positioning
+ the text with respect to its alignment point.
+ </p>
+ <p>
+ The rendered picture should match the reference image, except for
+ possible variations in the text fonts and layout (per CSS2 rules).
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-align-201-t.svg,v $</title>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="5" y="40" font-size="40" fill="black">Test of 'text-anchor'</text>
+ <text x="20" y="80" font-size="30" fill="black">text-anchor, text and tspan</text>
+ <!-- Test cases -->
+ <line x1="220" y1="120" x2="220" y2="260" stroke="red" />
+ <g font-family="Arial" font-size="30" fill="blue">
+ <text x="220" y="140" text-anchor="start">
+ start text
+ <tspan xml:space="preserve" fill="red"> red tspan</tspan>
+ </text>
+ <text x="220" y="180" text-anchor="middle" font-size="23">
+ first text <tspan font-weight="bold">first tspan</tspan> <tspan font-weight="bold">last tspan</tspan> last text
+ </text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-202-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-202-t.svg
new file mode 100644
index 0000000000..52c96d5f99
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-align-202-t.svg
@@ -0,0 +1,895 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="CL" desc="test alignment on RTL text" status="accepted"
+ approved="yes"
+ version="$Revision: 1.10 $" testname="$RCSfile: text-align-202-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>This test checks for text alignment on right-to-left text.</p>
+ <p>The first subtest has the word for 'Egypt', مص</p>
+ <p>The second subtest has the hebrew text פעילות </p>
+ <p>Text-anchor values of start are black, middle are maroon and end are dark blue.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-align-202-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <font xml:id="Untitled2" horiz-adv-x="537" >
+ <font-face
+ font-family="svgSerifHebrewArabic"
+ font-weight="500"
+ font-stretch="normal"
+ units-per-em="1000"
+ panose-1="2 0 6 3 0 0 0 0 0 0"
+ ascent="800"
+ descent="-200"
+ x-height="-1e+10"
+ cap-height="-1e+10"
+ bbox="11 -345 531 843"
+ underline-thickness="50"
+ underline-position="-100"
+ unicode-range="U+0590-U+06FF,U+FB50-U+FEFC"/>
+ <missing-glyph horiz-adv-x="432"
+ d="M33 0v666h333v-666h-333zM66 33h267v600h-267v-600z" />
+
+ <!-- ligatures -->
+ <glyph glyph-name="uniFDF2" unicode="&#x627;&#xfee0;&#xfee0;&#xfeea;" horiz-adv-x="640" arabic-form="isolated"
+ d="M918 261q45 0 45 87q0 110 -10 155l-29 132l55 29l19 -162q6 -65 8 -148v-20q0 -98 -13 -131t-59 -33q-109 2 -119 75q-12 -75 -111 -75q-60 0 -103 114l-34 -30q-54 1 -87 21t-33 50q0 23 9.5 42t30.5 34.5t33.5 23t40 20t28.5 12.5v45l31 34q3 -77 6.5 -122.5t10 -80.5
+ t19 -50.5t29.5 -22.5t44 -7q41 0 50.5 13.5t9.5 56.5q0 144 -24 271l55 41q3 -235 28 -342q8 -33 53 -33q2 0 6 0.5t7 0.5h4zM483 341q14 -23 31.5 -31t54.5 -8q16 0 23 1v107q-91 -34 -109 -69zM786 782q2 0 11 -15t22 -15q14 9 14 24q0 8 -3 15q3 6 6 6q3 1 7 -10t4 -37
+ q0 -16 -5.5 -22t-20.5 -6q-11 0 -29 5q-17 -21 -31 -21q-34 0 -34 41q0 18 2 30h2q3 1 5 -4t3 -11t4.5 -11.5t9.5 -5.5q7 0 19 6.5t12 18.5q0 5 -1 8q1 2 3 4zM790 853q-4 30 -28 67l28 30q5 -28 5 -57q0 -27 -5 -40z" />
+ <glyph glyph-name="uniFEFB" unicode="&#x0644;&#x0627;" horiz-adv-x="676" arabic-form="isolated"
+ d="M440 438c28 61.3333 53.3333 125.5 76 192.5c22.6667 67 35 116.5 37 148.5l-20 55c0 1.33331 -0.166687 3.66669 -0.5 7s-0.5 6 -0.5 8c0 26.6667 7 49 21 67v-14c0.666687 -18 21 -34 61 -48l-10 -52l-18 -19c-5.33331 -14 -9.83331 -33.5 -13.5 -58.5
+ s-13.3333 -62 -29 -111s-41.5 -115.167 -77.5 -198.5c39.3333 -70 59 -123 59 -159c0 -28.6667 -17.3333 -46.8333 -52 -54.5s-111 -12.5 -229 -14.5l6 91c81.3333 32.6667 137.667 75.6667 169 129l-141 212c-34.6667 51.3333 -53.6667 77.6667 -57 79
+ c-2.66667 0 -7.33333 -1.83331 -14 -5.5s-11.6667 -5.5 -15 -5.5c-12 0 -26.6667 9.16669 -44 27.5s-26 44.8333 -26 79.5c0 30.6667 6 46 18 46c14 0 42.1667 -27.5 84.5 -82.5c42.3333 -55 82.3333 -112.333 120 -172zM336 273c49.3333 1.33334 83 4.33334 101 9
+ s27 14 27 28c0 9.33334 -8 30.6667 -24 64c-30 -41.3333 -64.6667 -75 -104 -101z" />
+ <glyph glyph-name="uniFEFC" unicode="&#x0644;&#x0627;" horiz-adv-x="724" arabic-form="terminal"
+ d="M739 197h-48c-70 0 -105 54.6667 -105 164l-11 98c-30 -116.667 -75.6667 -195.667 -137 -237c-46.6667 -17.3333 -123.667 -26 -231 -26c-36 0 -64 0.333328 -84 1c110.667 35.3333 206.333 72.3333 287 111c98.6667 56.6667 148 174.667 148 354
+ c0 62 -4.66669 146 -14 252l120 -119c-28 -20 -42 -76.3333 -42 -169c0 -74.6667 9 -172.333 27 -293c14 -35.3333 29.3333 -53 46 -53h37zM438 445c-69.3333 144 -143.667 216 -223 216h-8l-3 144c66.6667 -4 117.333 -39.6667 152 -107s62 -151.667 82 -253z" />
+
+ <!-- ascii -->
+ <glyph unicode=" " horiz-adv-x="450"/>
+
+ <!-- hebrew -->
+ <glyph glyph-name="afii57664" unicode="&#x5d0;"
+ d="M71 51c0 9.33333 -6.16666 36.5 -18.5 81.5c-12.3333 45 -18.5 74.5 -18.5 88.5c0 34 21 75 63 123c-3.33334 0.666656 -8.33334 3.5 -15 8.5s-14.3333 12.3333 -23 22c-8.66667 9.66666 -16.1667 24.3333 -22.5 44c-6.33333 19.6667 -9.5 41.8333 -9.5 66.5
+ c0 24 6.33333 46 19 66s25.3333 30 38 30h2c1.33334 0 2.16666 -1 2.5 -3s0.833336 -6.66669 1.5 -14s2 -15.3333 4 -24c6 -22.6667 25.1667 -50.6667 57.5 -84c32.3333 -33.3333 63.1667 -61 92.5 -83c29.3333 -22 45.6667 -33 49 -33l51 71
+ c-5.33334 0 -20.5 11.5 -45.5 34.5s-37.5 42.8333 -37.5 59.5c0 16.6667 7.33334 34 22 52s29 27 43 27c4 0 6.16666 -1.33331 6.5 -4s0.166656 -6.33331 -0.5 -11v-6c0 -14 8.16666 -27.6667 24.5 -41c16.3333 -13.3333 34.1667 -25 53.5 -35s37.1667 -23.3333 53.5 -40
+ s24.5 -35 24.5 -55c0 -26.6667 -9.33334 -50.1667 -28 -70.5s-34 -30.5 -46 -30.5c-0.666656 0 -4.33334 15.6667 -11 47c-2.66666 13.3333 -7.33334 25 -14 35s-12.6667 16.6667 -18 20l-8 5l-49 -77c1.33334 0 8 -3.5 20 -10.5s26.5 -17.5 43.5 -31.5
+ s33.8333 -29.6667 50.5 -47s30.8333 -38 42.5 -62s17.5 -47.6667 17.5 -71c0 -41.3333 -4 -69 -12 -83s-18.6667 -21 -32 -21h-7c-0.666656 0 -1.5 6.33333 -2.5 19c-1 12.6667 -6.5 29.3333 -16.5 50c-10 20.6667 -25.3333 39 -46 55
+ c-42.6667 31.3333 -96.5 74.3333 -161.5 129c-65 54.6667 -97.8333 82 -98.5 82l-9 -7c-6 -4.66666 -12.1667 -12.1667 -18.5 -22.5s-9.5 -21.5 -9.5 -33.5c0 -15.3333 6.66666 -32.6667 20 -52s27.8333 -36.6667 43.5 -52c15.6667 -15.3333 30.1667 -33.1667 43.5 -53.5
+ c13.3333 -20.3333 20 -39.1667 20 -56.5c0 -12 -3.5 -22.1667 -10.5 -30.5c-7 -8.33333 -14.8333 -14 -23.5 -17s-16.6667 -6.5 -24 -10.5h-115l6 12c0.666668 2 2.66667 3 6 3c5.33333 0 9.33333 0.5 12 1.5s5.66667 2.66667 9 5c3.33334 2.33333 5.66666 6.33333 7 12
+ c1.33334 5.66667 2 13.1667 2 22.5z" />
+ <glyph glyph-name="afii57665" unicode="&#x5d1;"
+ d="M115 442c-26.6667 0 -46.6667 5.5 -60 16.5c-13.3333 11 -20 34.5 -20 70.5c0 36.6667 9.33333 59.6667 28 69c0 -2 1.33334 -5.5 4 -10.5s9 -10.3333 19 -16s22.3333 -8.5 37 -8.5h206c32 0 59.8333 -10.1667 83.5 -30.5s35.5 -57.1667 35.5 -110.5l2 -314h54l-35 -108
+
+ h-445l35 108h370v260c0 30.6667 -8.16666 50.6667 -24.5 60s-40.5 14 -72.5 14h-217z" />
+ <glyph glyph-name="afii57666" unicode="&#x5d2;" horiz-adv-x="350"
+ d="M141 433c-17.3333 0 -30.1667 5.33334 -38.5 16s-12.5 31.3333 -12.5 62c0 44 6.33334 73 19 87c0 -0.666687 0.833336 -2.33331 2.5 -5s4 -6.16669 7 -10.5l7.5 -10.5c4 -6 15.1667 -9.5 33.5 -10.5s37.3333 -3.33331 57 -7s32.8333 -11.8333 39.5 -24.5
+ c8.66666 -14.6667 13 -37.6667 13 -69v-22v-264c0 -29.3333 2.83334 -59 8.5 -89s11.8333 -58.6667 18.5 -86c-16.6667 0 -27.3333 0.666667 -32 2c-4.66666 1.33333 -7.83334 4.83333 -9.5 10.5c-1.66667 5.66667 -2.5 14.1667 -2.5 25.5
+ c-1.33333 10 -5.5 29.8333 -12.5 59.5s-10.5 44.8333 -10.5 45.5h-10l-62 -143h-118v4c0 67.3333 10 102 30 104l120 21c4.66667 4.66667 12.8333 14.6667 24.5 30s17.8333 27.3333 18.5 36c1.33333 16 5.16667 43.8333 11.5 83.5c6.33333 39.6667 9.5 65.8333 9.5 78.5
+ c0 6 -0.333328 10.3333 -1 13v4c0 15.3333 -4 29.8333 -12 43.5s-22 20.5 -42 20.5c-6 0 -15.5 -0.833344 -28.5 -2.5s-22.5 -2.5 -28.5 -2.5z" />
+ <glyph glyph-name="afii57667" unicode="&#x5d3;"
+ d="M53 596c0 -4.66669 4.5 -11.5 13.5 -20.5s23.1667 -13.5 42.5 -13.5h315c14.6667 0 28 -5.5 40 -16.5s18 -23.8333 18 -38.5c0 -17.3333 -4.5 -32.5 -13.5 -45.5s-20.8333 -19.5 -35.5 -19.5h-10v-350c0 -2.66666 0.166656 -5.83334 0.5 -9.5s0.5 -6.5 0.5 -8.5
+ c0 -10.6667 -3.66666 -26 -11 -46s-15.6667 -30 -25 -30h-2l-2 1c-0.666656 0 -1 3.33333 -1 10c0 2 0.166656 6.16667 0.5 12.5c0.333344 6.33333 0.5 11.1667 0.5 14.5l9 406h-281c-32.6667 0 -55.3333 6.83334 -68 20.5c-12.6667 13.6667 -19 33.8333 -19 60.5
+ c0 37.3333 9.33333 61.6667 28 73z" />
+ <glyph glyph-name="afii57668" unicode="&#x5d4;"
+ d="M52 598c0 -3.33331 1.16667 -7.33331 3.5 -12s8 -9.66669 17 -15s20.8333 -8 35.5 -8h315c12.6667 0 22.8333 -5.5 30.5 -16.5s11.5 -24.1667 11.5 -39.5c0 -43.3333 -14 -65 -42 -65h-10l5 -343c0 -2 1 -7.83334 3 -17.5s3 -17.5 3 -23.5
+ c0 -9.33333 -2.83334 -21.6667 -8.5 -37c-5.66666 -15.3333 -12.5 -23 -20.5 -23c-3.33334 0 -6 0.666667 -8 2c-0.666656 0 -1 2 -1 6c0 2.66667 0.166656 7.33333 0.5 14c0.333344 6.66667 0.5 11.6667 0.5 15l5 407h-280c-60 0 -90 28.6667 -90 86c0 32.6667 10 56 30 70
+ zM74 142c0 -16.6667 0.666664 -34.8333 2 -54.5s2 -30.1667 2 -31.5c0 -14 -2.16666 -27 -6.5 -39s-11.1667 -18 -20.5 -18l-1 1h-3c-4.66667 0 -7 16.6667 -7 50c0 2 0.166668 7 0.5 15s0.5 16.6667 0.5 26c0 8.66666 -0.333332 21 -1 37s-1 28 -1 36
+ c0 40.6667 4.83333 75.3333 14.5 104c9.66667 28.6667 19.1667 43 28.5 43c4 0 6 -6.33334 6 -19c0 -6 -2.33334 -25.6667 -7 -59c-4.66666 -33.3333 -7 -63.6667 -7 -91z" />
+ <glyph glyph-name="afii57669" unicode="&#x5d5;" horiz-adv-x="350"
+ d="M166 563c32.6667 0 53.8333 -6.33331 63.5 -19s14.5 -32.3333 14.5 -59c0 -6 -0.166672 -14.1667 -0.5 -24.5s-0.5 -17.5 -0.5 -21.5l12 -340c0 -14.6667 -2 -34.8333 -6 -60.5c-4 -25.6667 -9.33333 -38.5 -16 -38.5h-2c-0.666672 0 -3.33333 5 -8 15s-7 18.3333 -7 25
+ l7 325v7c0 13.3333 -7.66667 28.8333 -23 46.5s-34 26.5 -56 26.5c-4 0 -10 -0.166656 -18 -0.5s-13.6667 -0.5 -17 -0.5c-18.6667 0 -33.5 5.83334 -44.5 17.5s-16.5 26.5 -16.5 44.5c0 16 4 33.3333 12 52s15.6667 32 23 40l3 -10c2 -7.33331 5.5 -13.3333 10.5 -18
+ s12.1667 -7 21.5 -7c2.66666 0 6 -0.166687 10 -0.5s7 -0.5 9 -0.5c4 0 9.16667 0.166687 15.5 0.5s10.8333 0.5 13.5 0.5z" />
+ <glyph glyph-name="afii57670" unicode="&#x5d6;" horiz-adv-x="350"
+ d="M225 420c-4.66667 0 -8.5 2.16666 -11.5 6.5s-4.5 8.5 -4.5 12.5c0 4.66666 2 7 6 7c0 -0.666656 -3.66667 -1 -11 -1c-2 -5.33334 -6.16667 -12.5 -12.5 -21.5s-11.3333 -19 -15 -30s-5.5 -24.8333 -5.5 -41.5c0 -20.6667 5.33333 -54.6667 16 -102
+ c10.6667 -47.3333 16 -84 16 -110c0 -30.6667 -5.33333 -58.3333 -16 -83c-3.33333 -8 -6.16667 -17.5 -8.5 -28.5s-4.66667 -18.6667 -7 -23c-2.33333 -4.33333 -6.5 -6.5 -12.5 -6.5c-7.33333 0 -14 7.16667 -20 21.5c-6 14.3333 -9 25.5 -9 33.5
+ c0 0.666668 2.5 11.5 7.5 32.5s7.5 47.1667 7.5 78.5c0 15.3333 -0.833328 37.5 -2.5 66.5s-2.5 50.8333 -2.5 65.5c0 31.3333 1.66667 55.1667 5 71.5s8.83333 29.5 16.5 39.5l29.5 37c-2.66667 0 -7.66667 -0.166656 -15 -0.5s-13 -0.5 -17 -0.5
+ c-32.6667 0 -58.1667 7 -76.5 21s-27.5 39 -27.5 75c0 26.6667 7 46 21 58c0 -0.666687 4.33334 -4.83331 13 -12.5s14 -13.1667 16 -16.5c3.33334 -4.66669 24.3333 -7.33331 63 -8s61.3333 -3.66669 68 -9c20.6667 -16 31 -37 31 -63c0 -20.6667 -4 -37.3333 -12 -50
+ s-18 -19 -30 -19z" />
+ <glyph glyph-name="afii57671" unicode="&#x5d7;"
+ d="M65 -1c-5.33333 0 -9.33333 3.83333 -12 11.5c-2.66667 7.66667 -4 24.8333 -4 51.5l4 306c0.666668 15.3333 16 40 46 74c-26 0 -44.1667 8 -54.5 24s-15.5 39 -15.5 69c0 32.6667 7.66667 53.6667 23 63c4.66667 -9.33331 9.83333 -16.6667 15.5 -22
+ c5.66666 -5.33331 10.8333 -8.66669 15.5 -10s9.33334 -2.33331 14 -3s8.33334 -0.666687 11 0h315c13.3333 0 23.8333 -5.33331 31.5 -16s11.5 -24 11.5 -40c0 -43.3333 -14.3333 -65 -43 -65h-10l11 -345c0 -66 -8.66666 -99 -26 -99
+ c-5.33334 0 -9.16666 4.66667 -11.5 14c-2.33334 9.33333 -3.5 17 -3.5 23v407h-265c-20.6667 -30 -31 -54.6667 -31 -74v-314c0 -36.6667 -7.33334 -55 -22 -55z" />
+ <glyph glyph-name="afii57672" unicode="&#x5d8;"
+ d="M70 323c0 -26.6667 2.5 -67 7.5 -121s9.83334 -85.3333 14.5 -94h350c17.3333 50 26 121.667 26 215c0 37.3333 -7.83334 62 -23.5 74s-51.5 18 -107.5 18c-19.3333 0 -39.1667 -6.83334 -59.5 -20.5s-37 -28.6667 -50 -45l-37.5 -45.5
+ c-12 -14 -20.3333 -21.3333 -25 -22c-2 0 -3 1 -3 3c0 5.33334 14.6667 32.3333 44 81s47.3333 84.6667 54 108c16 59.3333 25 89 27 89c14.6667 1.33331 25 2 31 2c29.3333 0 55 -5 77 -15s39.1667 -23 51.5 -39s22.3333 -35.6667 30 -59s12.8333 -46 15.5 -68
+ s4 -46.6667 4 -74c0 -46.6667 -1.66666 -87.5 -5 -122.5s-7.5 -62.3333 -12.5 -82s-10.8333 -38.6667 -17.5 -57c-6.66666 -18.3333 -13.3333 -34.5 -20 -48.5h-400c1.33333 16 2 33.3333 2 52c0.666668 21.3333 1 49.3333 1 84c0 16 -0.166668 41.1667 -0.5 75.5
+ s-0.5 63.1667 -0.5 86.5c0 31.3333 3.5 59.3333 10.5 84s12.8333 40.5 17.5 47.5s8.33334 11.8333 11 14.5c-8 0 -19.1667 6.83334 -33.5 20.5s-21.5 31.1667 -21.5 52.5c0 18 3.16667 35.6667 9.5 53c6.33333 17.3333 14.8333 26.6667 25.5 28
+ c0 -12.6667 7.16666 -24.1667 21.5 -34.5s30 -19 47 -26s32.6667 -18.5 47 -34.5s21.5 -35 21.5 -57c0 -14.6667 -3 -29 -9 -43s-10.6667 -21.6667 -14 -23c0 3.33334 -13.3333 14.5 -40 33.5c-26.6667 19 -42 28.5 -46 28.5c-2 -2.66666 -4.33334 -7.5 -7 -14.5
+ s-5.5 -20.1667 -8.5 -39.5s-4.5 -41 -4.5 -65z" />
+ <glyph glyph-name="afii57673" unicode="&#x5d9;" horiz-adv-x="350"
+ d="M118 478c-17.3333 0 -31.1667 6 -41.5 18s-15.5 27.3333 -15.5 46c0 15.3333 3.16666 32 9.5 50s13.5 31 21.5 39c0 -5.33331 4.83334 -12.1667 14.5 -20.5s21.5 -12.5 35.5 -12.5c5.33333 0 13.6667 0.333313 25 1s20 1 26 1c22.6667 0 38.8333 -6.83331 48.5 -20.5
+ s14.5 -29.1667 14.5 -46.5c0 -24.6667 -5.83333 -66.1667 -17.5 -124.5s-21.5 -87.5 -29.5 -87.5c0 0.666656 0.5 4.16666 1.5 10.5s2.16667 14.6667 3.5 25s2 20.1667 2 29.5c0 34.6667 -6.83333 58.8333 -20.5 72.5s-29.5 20.5 -47.5 20.5
+ c-3.33333 0 -8.33333 -0.166656 -15 -0.5c-6.66666 -0.333344 -11.6667 -0.5 -15 -0.5z" />
+ <glyph glyph-name="afii57674" unicode="&#x5da;"
+ d="M62 564c0 -4.66669 5.33334 -11.8333 16 -21.5s21 -14.5 31 -14.5h325c13.3333 0 27 -6.33331 41 -19c14 -12.6667 21 -26.3333 21 -41c0 -16 -6.33334 -30.3333 -19 -43s-27 -19 -43 -19h-10c8 -304 12 -494.333 12 -571c0 -60 -0.333344 -105.333 -1 -136
+ c0 -29.3333 -7.33334 -44 -22 -44c-2.66666 0 -5 0.333344 -7 1c-1.33334 0 -5.33334 5.83334 -12 17.5s-10 20.8333 -10 27.5l11 705h-283c-57.3333 0 -86 23 -86 69c0 17.3333 3.66667 35 11 53c7.33333 18 15.6667 30 25 36z" />
+ <glyph glyph-name="afii57675" unicode="&#x5db;"
+ d="M101 442c-46.6667 0 -70 29 -70 87c0 35.3333 9.66667 58.3333 29 69c0 -2 1.33333 -5.33331 4 -10c2.66666 -4.66669 9 -10 19 -16s22.3333 -9 37 -9h246c24.6667 0 45.1667 -4.66669 61.5 -14s28.3333 -23 36 -41s12.8333 -36.5 15.5 -55.5s4 -41.5 4 -67.5
+ c0 -12 -0.333344 -29.5 -1 -52.5s-1 -39.8333 -1 -50.5c0 -12.6667 0.666656 -33.1667 2 -61.5s2 -49.5 2 -63.5c0 -49.3333 -7.16666 -87.8333 -21.5 -115.5c-14.3333 -27.6667 -41.8333 -41.5 -82.5 -41.5h-366l36 108h322c34 0 56 7.33334 66 22
+ c10 14.6667 15 40.6667 15 78c0 6.66667 -0.166656 18.1667 -0.5 34.5c-0.333344 16.3333 -0.5 29.5 -0.5 39.5v45c0 46 -5.16666 76.6667 -15.5 92s-35.8333 23 -76.5 23h-260z" />
+ <glyph glyph-name="afii57676" unicode="&#x5dc;"
+ d="M159 843c11.3333 0 21.5 -5.16669 30.5 -15.5s15.1667 -20.8333 18.5 -31.5l4 -16c0 -3.33331 -2.16667 -9.16669 -6.5 -17.5s-8.66667 -21.6667 -13 -40s-6.5 -41.5 -6.5 -69.5v-65h261c16 0 29.8333 -5.66669 41.5 -17s17.8333 -26.6667 18.5 -46l9 -204v-2
+ c0 -15.3333 -8.16666 -34.8333 -24.5 -58.5c-16.3333 -23.6667 -32.1667 -43.5 -47.5 -59.5s-37.6667 -38 -67 -66l-49 -47c-10.6667 -10.6667 -18 -20.6667 -22 -30c-4 -9.33333 -5.83334 -16 -5.5 -20s-1.33334 -7.16667 -5 -9.5s-11.5 -3.5 -23.5 -3.5
+ c-17.3333 0 -26 4.66667 -26 14c0 12 12.6667 30.1667 38 54.5s53.1667 48.3333 83.5 72s58.1667 49.6667 83.5 78c25.3333 28.3333 38 52.1667 38 71.5v6l-13 113c-5.33334 21.3333 -18.6667 32 -40 32l-302 2c-3.33333 0 -5 9.66666 -5 29v6l7 191
+ c0.666672 16.6667 6.16667 30.6667 16.5 42s15.5 22.3333 15.5 33c0 12.6667 -4.66667 21 -14 25s-14 12.6667 -14 26c0 15.3333 5.66667 23 17 23h2z" />
+ <glyph glyph-name="afii57677" unicode="&#x5dd;"
+ d="M389 563c22 0 42.6667 -9 62 -27s29 -47.6667 29 -89v-18l3 -427l-450 -2l11 334c0.666668 30.6667 8.16667 56.3333 22.5 77c14.3333 20.6667 25.8333 31 34.5 31h2h26h-1c-7.33334 0 -16.8333 -11 -28.5 -33s-17.5 -47 -17.5 -75v-226h382l1 280
+ c0 18.6667 -2.5 32.6667 -7.5 42s-14.8333 14 -29.5 14c-2.66666 0 -7.33334 -0.166656 -14 -0.5s-12 -0.5 -16 -0.5h-288c-31.3333 0 -53.6667 6.66666 -67 20c-13.3333 13.3333 -20 28.6667 -20 46c0 17.3333 4.83333 34.8333 14.5 52.5
+ c9.66667 17.6667 20.1667 29.8333 31.5 36.5c-0.666664 0 -1 -2.66669 -1 -8c0 -18 12.3333 -27 37 -27h284z" />
+ <glyph glyph-name="afii57678" unicode="&#x5de;"
+ d="M483 127c0 -14 0.333344 -25 1 -33v-12c0 -6 -6.66666 -21 -20 -45s-20 -36.3333 -20 -37h-335c0.666664 0 11.6667 17.6667 33 53c21.3333 35.3333 32.3333 53.6667 33 55h286l3 121v4c0 60.6667 -19.5 110.5 -58.5 149.5s-90.1667 58.5 -153.5 58.5
+ c-29.3333 0 -56 -6.33334 -80 -19s-42.8333 -28.1667 -56.5 -46.5c-13.6667 -18.3333 -25.1667 -38.5 -34.5 -60.5s-15.6667 -41.6667 -19 -59c-3.33333 -17.3333 -5 -32.3333 -5 -45c0 -7.33333 2.16667 -27.3333 6.5 -60c4.33334 -32.6667 6.5 -60.6667 6.5 -84
+ c0 -44 -7.33333 -66.3333 -22 -67c-2.66667 0 -5.83333 4 -9.5 12s-5.5 16.6667 -5.5 26v14c0 18 -1.66667 42.5 -5 73.5s-5 54.5 -5 70.5c0 36 6.16667 77.1667 18.5 123.5c12.3333 46.3333 33.8333 82.5 64.5 108.5c-3.33334 5.33334 -11.6667 12.1667 -25 20.5
+ s-24.6667 18.1667 -34 29.5s-14 25.6667 -14 43c0 15.3333 2.66667 30.8333 8 46.5s12 26.1667 20 31.5c0 -0.666687 8 -10.6667 24 -30c3.33334 -6 17 -11 41 -15s39.6667 -10.6667 47 -20c6 -7.33331 10.6667 -16.3333 14 -27c3.33333 -10.6667 5.66667 -20.6667 7 -30
+ s2.66667 -15 4 -17c1.33333 -3.33334 10.3333 -0.333344 27 9c14.6667 8.66666 27.1667 20.8333 37.5 36.5c10.3333 15.6667 17.8333 29.1667 22.5 40.5s7.33334 17 8 17c41.3333 -4 75.3333 -12.3333 102 -25s46.5 -29.6667 59.5 -51s21.6667 -42.8333 26 -64.5
+ s6.5 -47.8333 6.5 -78.5c0 -13.3333 -0.5 -34 -1.5 -62s-1.5 -49 -1.5 -63v-7c0 -3.33333 -0.166656 -15.1667 -0.5 -35.5s-0.5 -36.8333 -0.5 -49.5z" />
+ <glyph glyph-name="afii57679" unicode="&#x5df;" horiz-adv-x="350"
+ d="M122 416c-23.3333 0 -39.8333 7.33334 -49.5 22c-9.66667 14.6667 -14.5 31.3333 -14.5 50c0 32 12 57.3333 36 76c0 -4.66669 6.66666 -15.3333 20 -32c4 -5.33331 20.1667 -9.33331 48.5 -12s46.1667 -6.33331 53.5 -11c22.6667 -15.3333 34 -34 34 -56
+ c0 -23.3333 -9.5 -53.1667 -28.5 -89.5s-28.5 -73.5 -28.5 -111.5l12 -495v-4c0 -19.3333 -2.83333 -40.1667 -8.5 -62.5s-14.5 -33.5 -26.5 -33.5h-4c-4.66667 0 -7 12.3333 -7 37l14 558c0 16.6667 4.16667 37.3333 12.5 62s12.5 40.3333 12.5 47c0 37.3333 -17 56 -51 56
+ c-2.66667 0 -6.83333 -0.166656 -12.5 -0.5s-9.83334 -0.5 -12.5 -0.5z" />
+ <glyph glyph-name="afii57680" unicode="&#x5e0;" horiz-adv-x="350"
+ d="M144 444c-24 0 -41.5 5.83334 -52.5 17.5s-16.5 35.1667 -16.5 70.5c0 33.3333 5.33334 55.3333 16 66c0 -0.666687 2.66666 -4 8 -10s9 -10.6667 11 -14c4.66666 -6.66669 20 -10 46 -10h13c37.3333 0 62.1667 -7.5 74.5 -22.5s18.5 -49.1667 18.5 -102.5
+ c1.33334 -8 2 -56 2 -144c0 -73.3333 -0.666656 -142.667 -2 -208c0 -0.666664 -7.16667 -14.8333 -21.5 -42.5c-14.3333 -27.6667 -21.5 -42.5 -21.5 -44.5h-172l55 108h129l16 269v7c0 16 -4.5 30.1667 -13.5 42.5s-25.5 18.5 -49.5 18.5
+ c-4 0 -10.6667 -0.166656 -20 -0.5s-16 -0.5 -20 -0.5z" />
+ <glyph glyph-name="afii57681" unicode="&#x5e1;"
+ d="M59 283c0 -62.6667 6.33334 -107.5 19 -134.5s40 -40.5 82 -40.5h157c5.33334 0 13.1667 -0.166664 23.5 -0.5s17.8333 -0.5 22.5 -0.5c18.6667 0 33.5 1.66666 44.5 5s21.8333 10.6667 32.5 22c10.6667 11.3333 18.3333 29.1667 23 53.5s7 55.8333 7 94.5
+ c0 60.6667 -7.16666 102.5 -21.5 125.5s-43.1667 34.5 -86.5 34.5h-257c0 -3.33334 -2.5 -8.66666 -7.5 -16l-16 -24c-5.66666 -8.66666 -10.8333 -23.5 -15.5 -44.5c-4.66667 -21 -7 -45.8333 -7 -74.5zM79 443c-28.6667 3.33334 -43 29 -43 77c0 42 8.66667 68 26 78
+ c0 -1.33331 1.33333 -4.5 4 -9.5c2.66666 -5 9 -10.5 19 -16.5s22 -9 36 -9h246c22 0 40.8333 -4.16669 56.5 -12.5s27.8333 -18.8333 36.5 -31.5c8.66666 -12.6667 15.5 -29.1667 20.5 -49.5s8.16666 -39.1667 9.5 -56.5s2 -38 2 -62c0 -8 -0.166656 -19.6667 -0.5 -35
+ s-0.5 -26.6667 -0.5 -34c0 -95.3333 -15.1667 -166.167 -45.5 -212.5c-30.3333 -46.3333 -73.1667 -69.5 -128.5 -69.5h-157c-23.3333 0 -43.1667 3.66667 -59.5 11c-16.3333 7.33333 -29.1667 16.5 -38.5 27.5c-9.33333 11 -16.3333 26.5 -21 46.5s-7.66667 39 -9 57
+ c-1.33333 18 -2 41.3333 -2 70v70c0 64 16.3333 117.667 49 161z" />
+ <glyph glyph-name="afii57682" unicode="&#x5e2;"
+ d="M414 564c25.3333 0 42.5 -4.66669 51.5 -14s13.5 -28 13.5 -56c0 -50 -13.3333 -131 -40 -243s-50.3333 -175.667 -71 -191c-12 -8 -74.6667 -20 -188 -36l-169 -24c8.66667 15.3333 18 36.3333 28 63c10 26.6667 15 43 15 49l136 27l-31.5 68
+ c-11 22.6667 -20.8333 46 -29.5 70c-8.66666 24 -13 42.6667 -13 56c0 9.33334 2.16666 20.5 6.5 33.5s9.16667 24.1667 14.5 33.5l15 26l7 12c0 -0.666656 -3 -1 -9 -1c-22 0 -37 6.5 -45 19.5s-12 31.5 -12 55.5c0 52 8.66666 81 26 87c0 -2 1 -5.16669 3 -9.5
+ s6.66667 -9 14 -14s16.3333 -7.5 27 -7.5h7c50 0 75 -25 75 -75c0 -17.3333 -2.66667 -34.6667 -8 -52s-9.66667 -27 -13 -29c0 4 -5.33333 8.83334 -16 14.5s-24.6667 8.5 -42 8.5l-6 -15c-4 -10 -8 -22.6667 -12 -38s-6 -29.6667 -6 -43c0 -14 2.5 -27.5 7.5 -40.5
+ s14 -33.6667 27 -62c13 -28.3333 25.1667 -59.1667 36.5 -92.5c5.33333 0 32.1667 4 80.5 12c48.3333 8 73.8333 13.3333 76.5 16c21.3333 32.6667 38.1667 70.8333 50.5 114.5c12.3333 43.6667 18.5 81.8333 18.5 114.5v4c0 12 -5.16666 20 -15.5 24s-22 5.66666 -35 5
+ s-25.6667 2.16666 -38 8.5s-19.8333 17.5 -22.5 33.5c-1.33334 4.66666 -2 12.6667 -2 24c0 21.3333 3.16666 42.1667 9.5 62.5s14.5 32.8333 24.5 37.5l7 -8c4.66666 -6 7.66666 -11.6667 9 -17c4 -7.33331 15.3333 -11 34 -11h4z" />
+ <glyph glyph-name="afii57683" unicode="&#x5e3;"
+ d="M174 182c31.3333 0 54.6667 7.16667 70 21.5c15.3333 14.3333 23 42.1667 23 83.5c0 25.3333 -5.16666 42.3333 -15.5 51c-10.3333 8.66666 -26.5 13 -48.5 13c-7.33333 0 -20.6667 -0.5 -40 -1.5s-35 -1.5 -47 -1.5c-28 0 -42 6 -42 18c0 6.66666 3.66666 14 11 22
+ s14.3333 14 21 18c4.66666 0 11.3333 0.166656 20 0.5c8.66667 0.333344 15 0.5 19 0.5h154c43.3333 0 77.5 -13.3333 102.5 -40s37.5 -74 37.5 -142c0 -6 -1.16666 -47.5 -3.5 -124.5s-3.5 -141.167 -3.5 -192.5c0 -164.667 11 -247 33 -247c13.3333 0 20 59.3333 20 178
+ c0 70.6667 -2.33334 154.667 -7 252l-7 146v26c0 176.667 -56 265 -168 265h-193c-40 0 -60 11.6667 -60 35c-17.3333 -8.66669 -26 -35.3333 -26 -80c0 -24 4.33333 -41.3333 13 -52c8.66667 -10.6667 24.6667 -18.6667 48 -24
+ c-13.3333 -14.6667 -26.8333 -33.8333 -40.5 -57.5c-13.6667 -23.6667 -20.5 -48.8333 -20.5 -75.5c0 -10 5.16667 -23.3333 15.5 -40c10.3333 -16.6667 20.1667 -27.6667 29.5 -33c18 -12.6667 53 -19 105 -19z" />
+ <glyph glyph-name="afii57684" unicode="&#x5e4;"
+ d="M175 216c32 0 55.3333 7.33333 70 22c14.6667 14.6667 22 41.3333 22 80c0 27.3333 -5.16666 45.5 -15.5 54.5c-10.3333 9 -26.8333 13.5 -49.5 13.5c-6.66667 0 -19.5 -0.5 -38.5 -1.5s-34.5 -1.5 -46.5 -1.5c-28 0 -42 6.33334 -42 19c0 6 3.66666 13 11 21
+ s14.3333 13.6667 21 17c4.66666 0 11.3333 0.333344 20 1c8.66667 0.666656 15 1 19 1h154c25.3333 0 46.1667 -2.66666 62.5 -8s30.1667 -17 41.5 -35c14.6667 -24 25.1667 -44.8333 31.5 -62.5s9.83334 -39.8333 10.5 -66.5l6 -162h-398l-35 -108h417
+ c2 4.66667 8.5 23.6667 19.5 57c11 33.3333 16.5 50.3333 16.5 51v164c0 29.3333 -0.666656 55.1667 -2 77.5s-5.33334 47.8333 -12 76.5s-15.6667 52.1667 -27 70.5c-11.3333 18.3333 -27.8333 34 -49.5 47s-47.5 19.5 -77.5 19.5h-193c-40 0 -60 11.6667 -60 35
+ c-18 -9.33331 -27 -36 -27 -80c0 -24 4.5 -41.1667 13.5 -51.5s25.1667 -18.5 48.5 -24.5l-11 -14c-7.33334 -9.33334 -14.5 -19 -21.5 -29s-13.6667 -23.5 -20 -40.5c-6.33333 -17 -9.5 -33.5 -9.5 -49.5c0 -10 5.33333 -23.3333 16 -40
+ c10.6667 -16.6667 20.3333 -28 29 -34c19.3333 -12.6667 54.6667 -19 106 -19z" />
+ <glyph glyph-name="afii57685" unicode="&#x5e5;"
+ d="M443 361c-6.66666 6.66666 -13 13.3333 -19 20s-10 11 -12 13s-4.16666 3.66666 -6.5 5s-4.83334 2 -7.5 2s-7.16666 -0.666656 -13.5 -2s-10.8333 -2 -13.5 -2c-4.66666 -4 -18.1667 -14 -40.5 -30s-41.3333 -31.3333 -57 -46s-29.5 -30.3333 -41.5 -47
+ c-13.3333 -20 -23.8333 -72.3333 -31.5 -157c-7.66667 -84.6667 -17.1667 -139.667 -28.5 -165l4 -195v-3c0 -19.3333 -3.5 -40.5 -10.5 -63.5s-17.8333 -34.5 -32.5 -34.5c-5.33334 0 -9.16666 4.66666 -11.5 14s-3.5 16.6667 -3.5 22l13 633
+ c0 4.66666 3.66667 11.1667 11 19.5s11 15.8333 11 22.5c0 14.6667 -6.66667 25.3333 -20 32c-13.3333 6.66666 -28.1667 10.5 -44.5 11.5s-31.1667 6.33334 -44.5 16c-13.3333 9.66666 -20 24.8333 -20 45.5c0 17.3333 3.66667 35.1667 11 53.5
+ c7.33333 18.3333 15.6667 31.1667 25 38.5c0 -1.33331 3.83333 -5.66669 11.5 -13c7.66666 -7.33331 12.5 -12.3333 14.5 -15c4 -5.33331 15.5 -9.16669 34.5 -11.5s32.5 -5.83331 40.5 -10.5c23.3333 -16 35 -39.6667 35 -71c0 -24 -7.5 -51.5 -22.5 -82.5
+ s-22.5 -67.1667 -22.5 -108.5l6 -230c3.33333 8.66667 11.1667 52.5 23.5 131.5s24.5 126.833 36.5 143.5c10.6667 14.6667 22.6667 28.3333 36 41c13.3333 12.6667 30.1667 26.3333 50.5 41s33.5 24.6667 39.5 30c-8 4.66666 -14.1667 14.5 -18.5 29.5s-6.5 27.5 -6.5 37.5
+ c0 16 4.5 31.8333 13.5 47.5c9 15.6667 19.5 26.1667 31.5 31.5c0 -1.33331 4.16666 -5.66669 12.5 -13s13.5 -13.3333 15.5 -18c2.66666 -6.66669 9 -10.8333 19 -12.5c10 -1.66666 20.1667 -5.16666 30.5 -10.5s17.5 -15.3333 21.5 -30c5.33334 -17.3333 8 -34.3333 8 -51
+ c0 -30.6667 -9 -50.3333 -27 -59z" />
+ <glyph glyph-name="afii57686" unicode="&#x5e6;"
+ d="M369 598c0 -13.3333 5.5 -23.8333 16.5 -31.5s23.3333 -13 37 -16s26 -10.8333 37 -23.5s16.5 -30 16.5 -52c0 -16.6667 -3.83334 -32.3333 -11.5 -47s-17.5 -24.6667 -29.5 -30c0 23.3333 -16.3333 39 -49 47l-40 -192c18 -8.66667 30.5 -15.1667 37.5 -19.5
+ s14.1667 -10.1667 21.5 -17.5s16.6667 -17.3333 28 -30c16.6667 -16.6667 28 -32.6667 34 -48c6 -15.3333 9 -35.3333 9 -60c0 -14.6667 -3.5 -30.3333 -10.5 -47c-7 -16.6667 -12.5 -27 -16.5 -31h-436c32 55.3333 49.6667 91.3333 53 108h314
+ c0 13.3333 -2.33334 23.6667 -7 31c-18.6667 23.3333 -39.8333 40.8333 -63.5 52.5s-45.1667 18.5 -64.5 20.5c-19.3333 2 -37.6667 4.16667 -55 6.5s-30.8333 8.16667 -40.5 17.5s-14.5 24.6667 -14.5 46c0 9.33334 0.5 25.3333 1.5 48s1.5 39.6667 1.5 51
+ c0 29.3333 -3.5 49 -10.5 59s-19.5 15 -37.5 15h-20c-20 0 -34.3333 5.83334 -43 17.5c-8.66667 11.6667 -13 25.1667 -13 40.5c0 16 3.83333 32.5 11.5 49.5c7.66667 17 16.1667 28.8333 25.5 35.5c0 -11.3333 4.33333 -19.6667 13 -25
+ c8.66666 -5.33331 18.5 -8.33331 29.5 -9s22.5 -3.16669 34.5 -7.5s20.6667 -11.1667 26 -20.5c7.33333 -11.3333 11 -43 11 -95c0 -9.33334 -0.166672 -24 -0.5 -44s-0.5 -34.6667 -0.5 -44s55 -39.6667 165 -91l39 191c-28 9.33334 -42 29.3333 -42 60
+ c0 17.3333 4.16666 34.5 12.5 51.5s18.5 28.1667 30.5 33.5z" />
+ <glyph glyph-name="afii57687" unicode="&#x5e7;"
+ d="M457 230c0 41.3333 -2.33334 73.6667 -7 97s-13.6667 41 -27 53s-28 19.5 -44 22.5s-39.3333 4.5 -70 4.5h-206c-22.6667 0 -38.5 1.66666 -47.5 5s-13.8333 8.66666 -14.5 16s-2 16.6667 -4 28c-3.33333 12 -5 25 -5 39c0 33.3333 9.66667 56.3333 29 69
+ c0 -6 5.33334 -13.6667 16 -23s24.6667 -14 42 -14h194c22.6667 0 41.6667 -1.16669 57 -3.5s28.8333 -6.33331 40.5 -12c11.6667 -5.66666 20.8333 -13.3333 27.5 -23s12.5 -21.6667 17.5 -36s8.66666 -31.3333 11 -51l8 -68c3 -25.6667 5.5 -54.8333 7.5 -87.5
+ c0.666656 -4.66667 1 -11.6667 1 -21c0 -21.3333 -2.66666 -39.8333 -8 -55.5s-15 -29.8333 -29 -42.5c-14 -12.6667 -25.6667 -22.1667 -35 -28.5s-25.8333 -15.3333 -49.5 -27c-23.6667 -11.6667 -40.1667 -20.1667 -49.5 -25.5
+ c-46.6667 -26.6667 -83.1667 -46.8333 -109.5 -60.5c-26.3333 -13.6667 -45.5 -20.5 -57.5 -20.5c-3.33333 0 -5 1 -5 3c0 6 18 21.3333 54 46c36 24.6667 76 49.6667 120 75c9.33334 5.33334 22.6667 11.8333 40 19.5s30.8333 14.1667 40.5 19.5
+ c9.66666 5.33333 20 12.5 31 21.5s19 20.1667 24 33.5s7.5 29 7.5 47zM76 -153c0 -66.6667 -3.33334 -112.333 -10 -137c-6.66667 -24.6667 -21.3333 -42.3333 -44 -53c-0.666666 0 -1 1.33334 -1 4s1.66667 19.3333 5 50s5 54.6667 5 72c0 4.66667 -0.5 34.5 -1.5 89.5
+ s-1.5 119.833 -1.5 194.5v150c0 23.3333 3 45.6667 9 67s11.3333 32 16 32c2 0 5.16667 -6 9.5 -18c4.33334 -12 6.5 -26 6.5 -42c0 -7.33333 -0.833336 -17.6667 -2.5 -31s-2.5 -32.3333 -2.5 -57c0 -28.6667 2 -81.5 6 -158.5s6 -131.167 6 -162.5z" />
+ <glyph glyph-name="afii57688" unicode="&#x5e8;"
+ d="M336 563c14 0 27.3333 -1.83331 40 -5.5s25.3333 -9.66669 38 -18s23 -21.1667 31 -38.5c8 -17.3333 12.3333 -38 13 -62l1 -18c0.666656 -12 1.66666 -28.1667 3 -48.5s2.5 -42.6667 3.5 -67s1.83334 -51.5 2.5 -81.5s1 -57.6667 1 -83c0 -36 -0.666656 -63.6667 -2 -83
+ c-1.33334 -19.3333 -2 -29.3333 -2 -30v-12c0 -11.3333 -2.66666 -17 -8 -17c-2.66666 0 -4.66666 0.333333 -6 1c-2 0 -6.5 4.16667 -13.5 12.5c-7 8.33333 -10.5 15.5 -10.5 21.5v1l11 267v20c0 50.6667 -3.5 83.6667 -10.5 99s-18.1667 23 -33.5 23
+ c-3.33334 0 -11.3333 -0.333344 -24 -1s-24 -1 -34 -1h-225c-30 0 -52 5.5 -66 16.5s-21 32.5 -21 64.5c0 40 9 65 27 75c0 -4.66669 5.33333 -11.6667 16 -21c10.6667 -9.33331 24 -14 40 -14h229z" />
+ <glyph glyph-name="afii57689" unicode="&#x5e9;"
+ d="M81 455c-13.3333 0 -25.3333 4.16666 -36 12.5s-16 22.5 -16 42.5c0 18 3.66667 36.6667 11 56s17 30 29 32l8 -10c5.33334 -6.66669 8.66666 -13 10 -19c2 -6.66669 6 -11.1667 12 -13.5s12.3333 -3.33331 19 -3s13.6667 -1.66669 21 -6s13 -11.5 17 -21.5s6 -20 6 -30
+ c0 -16.6667 -4.33333 -32.8333 -13 -48.5s-15 -24.5 -19 -26.5c0 8.66666 -3.33334 15.8333 -10 21.5s-16 8.5 -28 8.5l-6 -13c-3.33334 -8.66666 -6.83334 -21.1667 -10.5 -37.5s-5.5 -33.8333 -5.5 -52.5c0 -28.6667 7 -71.8333 21 -129.5
+ c14 -57.6667 27.6667 -94.1667 41 -109.5c21.3333 34 49.8333 96.6667 85.5 188c35.6667 91.3333 53.5 143.667 53.5 157h-2c-18 0 -32.6667 4.83334 -44 14.5s-17 22.8333 -17 39.5c0 16.6667 4.5 35.5 13.5 56.5s19.1667 32.5 30.5 34.5c0 -0.666687 2 -4.16669 6 -10.5
+ s6.66666 -12.5 8 -18.5c1.33334 -8 6.33334 -12.5 15 -13.5s18.5 -3.16669 29.5 -6.5s19.1667 -11.3333 24.5 -24c4.66666 -11.3333 7 -22.6667 7 -34c0 -16.6667 -3.5 -32.1667 -10.5 -46.5s-12.5 -22.5 -16.5 -24.5c-2.66666 16.6667 -12.3333 25 -29 25
+ c0 -24.6667 -41.3333 -137 -124 -337h239c28 4 52.6667 41.6667 74 113c21.3333 71.3333 32 139.667 32 205c0 11.3333 -5.16666 19 -15.5 23s-21.8333 5.83334 -34.5 5.5s-25.1667 3 -37.5 10s-20.1667 18.5 -23.5 34.5c-0.666656 2.66666 -1 6.66666 -1 12
+ c0 16.6667 4.33334 34 13 52s19 29.6667 31 35c0 -1.33331 2.16666 -5.66669 6.5 -13s7.16666 -13 8.5 -17c2.66666 -7.33331 12.6667 -12.3333 30 -15s30 -12.3333 38 -29c6 -13.3333 9 -34.6667 9 -64c0 -59.3333 -9.16669 -127 -27.5 -203
+ c-18.3333 -76 -36.3333 -136.833 -54 -182.5c-17.6667 -45.6667 -28.5 -70.5 -32.5 -74.5h-332c0 6.66667 -0.833336 16.5 -2.5 29.5s-2.5 23.8333 -2.5 32.5c-2 30 -10 69 -24 117s-21 90.6667 -21 128c0 15.3333 1.16667 30.3333 3.5 45s5.33333 27 9 37
+ s7.66667 19.5 12 28.5s8.33334 15.8333 12 20.5l9.5 12l4 5h-4z" />
+ <glyph glyph-name="afii57690" unicode="&#x5ea;"
+ d="M71 598c0 -2.66669 1.16666 -6.33331 3.5 -11s8.16666 -9.83331 17.5 -15.5s21.3333 -8.5 36 -8.5h232c37.3333 0 60.8333 -1.83331 70.5 -5.5s21.1667 -14.5 34.5 -32.5c5.33334 -7.33331 9.33334 -15.6667 12 -25s4.16666 -18.8333 4.5 -28.5s0.833344 -20.5 1.5 -32.5
+ l15 -340v-17c0 -55.3333 -7 -83 -21 -83c-0.666656 0 -1 0.333333 -1 1h-2c-2 0 -6.5 4.33333 -13.5 13c-7 8.66667 -10.1667 16 -9.5 22l17 353c0 18 -2.33334 31.8333 -7 41.5s-14.3333 14.5 -29 14.5c-3.33334 0 -8.5 -0.333344 -15.5 -1s-12.5 -1 -16.5 -1h-294
+ c-1.33334 -4.66666 -4 -10.8333 -8 -18.5s-8.33334 -23 -13 -46s-7 -47.1667 -7 -72.5c0 -22.6667 5 -43.6667 15 -63c10 -19.3333 20.8333 -35 32.5 -47c11.6667 -12 22.5 -26.3333 32.5 -43s15 -33.3333 15 -50c0 -23.3333 -6.33333 -46.1667 -19 -68.5
+ c-12.6667 -22.3333 -29.3333 -33.5 -50 -33.5h-71c-0.666668 0.666667 -1 7.66667 -1 21c0 35.3333 2 59 6 71s11.6667 18 23 18c16.6667 0 30 -1.66666 40 -5c-5.33334 12 -12.3333 25 -21 39s-16.8333 33.5 -24.5 58.5s-11.5 49.1667 -11.5 72.5
+ c0 69.3333 15.6667 125 47 167c-11.3333 0 -22.3333 8.16666 -33 24.5c-10.6667 16.3333 -16 36.8333 -16 61.5c0 38 9.66667 61.3333 29 70z" />
+ <glyph glyph-name="afii57716" unicode="&#x5f0;"
+ d="M406 563c32 0 53.1667 -6.5 63.5 -19.5s15.5 -35.8333 15.5 -68.5v-21v-15l10 -340c0 -14.6667 -2 -34.8333 -6 -60.5c-4 -25.6667 -9.33334 -38.5 -16 -38.5h-2c-0.666656 0 -3.16666 5 -7.5 15s-6.5 18.3333 -6.5 25l6 325v7c0 12 -7.16666 27.1667 -21.5 45.5
+ s-33.5 27.5 -57.5 27.5c-4 0 -9.66666 -0.166656 -17 -0.5s-13 -0.5 -17 -0.5c-18.6667 0 -33.5 5.66666 -44.5 17s-16.5 25.6667 -16.5 43c0 16 4 33.6667 12 53s15.3333 33 22 41l3 -10c2 -7.33331 5.5 -13.3333 10.5 -18s12.1667 -7 21.5 -7
+ c2.66666 0 6.16666 -0.166687 10.5 -0.5s7.16666 -0.5 8.5 -0.5c4.66666 0 10 0.166687 16 0.5s10.3333 0.5 13 0.5zM146 563c32 0 53 -6.66669 63 -20s15 -33.3333 15 -60c0 -4.66666 -0.166672 -11.3333 -0.5 -20s-0.5 -14.6667 -0.5 -18v-6l12 -340c0 -14 -2 -34 -6 -60
+ s-9.33333 -39 -16 -39h-2c-2 0 -5 5 -9 15s-6 18.3333 -6 25l7 325c0 14.6667 -6.66667 31.6667 -20 51s-33 29 -59 29c-4 0 -10 -0.166656 -18 -0.5s-13.6667 -0.5 -17 -0.5c-18.6667 0 -33.5 5.83334 -44.5 17.5s-16.5 26.5 -16.5 44.5c0 16 4 33.3333 12 52
+ s15.6667 32 23 40c0 -0.666687 0.666668 -3.16669 2 -7.5c1.33334 -4.33331 2.83334 -8.33331 4.5 -12s5 -7.16669 10 -10.5s11.1667 -5 18.5 -5c2.66666 0 6 -0.166687 10 -0.5s7 -0.5 9 -0.5c4 0 9.16666 0.166687 15.5 0.5c6.33333 0.333313 10.8333 0.5 13.5 0.5z" />
+ <glyph glyph-name="afii57717" unicode="&#x5f1;"
+ d="M407 563c32.6667 0 53.8333 -6.83331 63.5 -20.5s14.5 -34.5 14.5 -62.5v-35v-6l10 -340c0 -14.6667 -2 -34.8333 -6 -60.5c-4 -25.6667 -9.33334 -38.5 -16 -38.5h-2c-0.666656 0 -3.33334 5 -8 15s-7 18.3333 -7 25l8 325v5c0 14.6667 -7.5 30.8333 -22.5 48.5
+ s-33.8333 26.5 -56.5 26.5c-4 0 -10 -0.166656 -18 -0.5s-13.6667 -0.5 -17 -0.5c-18 0 -32.6667 5.66666 -44 17s-17 26 -17 44c0 16 4 33.5 12 52.5s15.6667 32.5 23 40.5l3 -10c2 -7.33331 5.5 -13.3333 10.5 -18s12.1667 -7 21.5 -7
+ c2.66666 0 6.16666 -0.166687 10.5 -0.5s7.16666 -0.5 8.5 -0.5c4 0 9.33334 0.166687 16 0.5s11 0.5 13 0.5zM91 445c-17.3333 0 -31.3333 6.16666 -42 18.5s-16 27.8333 -16 46.5c0 15.3333 3 31.8333 9 49.5s13 30.5 21 38.5c0 -4.66669 5.16666 -11.3333 15.5 -20
+ s23.1667 -13 38.5 -13c4.66666 0 12.6667 0.333313 24 1s19.6667 1 25 1c22 0 37.6667 -7 47 -21s14 -29.3333 14 -46c0 -24 -5.83333 -65.1667 -17.5 -123.5s-21.1667 -87.5 -28.5 -87.5v1c0 0.666656 0.5 4.5 1.5 11.5s2.16667 15.6667 3.5 26s2 20.1667 2 29.5
+ c0 33.3333 -7 56.5 -21 69.5s-30 19.5 -48 19.5c-3.33334 0 -8 -0.166656 -14 -0.5s-10.6667 -0.5 -14 -0.5z" />
+ <glyph glyph-name="afii57718" unicode="&#x5f2;"
+ d="M349 478c-17.3333 0 -31.1667 6 -41.5 18s-15.5 27.3333 -15.5 46c0 15.3333 3.16666 32 9.5 50s13.1667 31 20.5 39c0 -5.33331 4.83334 -12.1667 14.5 -20.5s21.5 -12.5 35.5 -12.5c5.33334 0 13.6667 0.333313 25 1s20 1 26 1c22.6667 0 38.8333 -6.83331 48.5 -20.5
+ s14.5 -29.1667 14.5 -46.5c0 -22.6667 -6 -63.6667 -18 -123s-21.3333 -89 -28 -89v1c0 0.666656 0.666656 4.5 2 11.5s2.5 15.6667 3.5 26s1.5 20.1667 1.5 29.5c0 33.3333 -6.83334 56.6667 -20.5 70s-29.5 20 -47.5 20c-3.33334 0 -8.33334 -0.166656 -15 -0.5
+ s-11.6667 -0.5 -15 -0.5zM88 478c-17.3333 0 -31.1667 6 -41.5 18s-15.5 27.3333 -15.5 46c0 15.3333 3 32 9 50s12.6667 31 20 39c0 -4 5.16666 -10.5 15.5 -19.5s22.5 -13.5 36.5 -13.5c4.66666 0 12.6667 0.333313 24 1c11.3333 0.666687 20 1 26 1
+ c22.6667 0 38.8333 -7 48.5 -21s14.5 -29.3333 14.5 -46c0 -24 -5.83333 -65.3333 -17.5 -124s-21.1667 -88 -28.5 -88v1c0 0.666656 1 8.83334 3 24.5s3 29.5 3 41.5c0 33.3333 -6.66667 56.8333 -20 70.5s-29 20.5 -47 20.5c-3.33334 0 -8.33334 -0.166656 -15 -0.5
+ s-11.6667 -0.5 -15 -0.5z" />
+ <glyph glyph-name="uni05F3" unicode="&#x5f3;" horiz-adv-x="396"
+ d="M283 727c5.33334 0 9 -1.16669 11 -3.5s3 -7.5 3 -15.5c0 -24 -11.8333 -53 -35.5 -87c-23.6667 -34 -48.1667 -62.6667 -73.5 -86c-25.3333 -23.3333 -42.3333 -35 -51 -35c-3.33333 0 -5 2 -5 6c0 12.6667 10.6667 39.3333 32 80s40.6667 73 58 97
+ c13.3333 17.3333 24.1667 29 32.5 35c8.33334 6 17.8333 9 28.5 9z" />
+ <glyph glyph-name="uni05F4" unicode="&#x5f4;" horiz-adv-x="396"
+ d="M197 727c5.33333 0 8.83333 -1 10.5 -3s2.5 -7 2.5 -15c0 -24 -11.8333 -53.1667 -35.5 -87.5s-48.3333 -63.1667 -74 -86.5c-25.6667 -23.3333 -42.5 -35 -50.5 -35c-3.33333 0 -5 2 -5 6c0 12.6667 10.6667 39.5 32 80.5c21.3333 41 41 73.1667 59 96.5
+ c13.3333 18 24 29.8333 32 35.5s17.6667 8.5 29 8.5zM332 727c5.33334 0 9 -1.16669 11 -3.5s3 -7.5 3 -15.5c0 -24 -11.8333 -53 -35.5 -87s-48.3333 -62.6667 -74 -86c-25.6667 -23.3333 -42.8333 -35 -51.5 -35c-3.33333 0 -5 2 -5 6c0 12 10.8333 38.6667 32.5 80
+ s41.1667 73.6667 58.5 97c13.3333 17.3333 24.1667 29 32.5 35s17.8333 9 28.5 9z" />
+
+ <!-- arabic -->
+ <glyph glyph-name="afii57388" unicode="&#x60c;" horiz-adv-x="226"
+ d="M245 256q-10 -60 -67 -61q-67 0 -79 64q1 9 0 19t2 24t7.5 28t16 31.5t28.5 34.5t47 28l18 -1q-50 -44 -74 -89q34 2 44 2q17 0 28.5 -7t17 -21t8 -25t3.5 -27z" />
+ <glyph glyph-name="afii57403" unicode="&#x61b;" horiz-adv-x="250"
+ d="M143 395q-38 0 -63.5 28t-25.5 72q0 133 109 227l19 -26q-69 -69 -69 -115q0 -12 11.5 -17.5t26.5 -6t32.5 -9t26.5 -25.5q8 -18 8 -38v-13q-1 -9 -4.5 -19.5t-11 -25t-23 -23.5t-36.5 -9zM150 322q58 0 68 -73q-9 -68 -62 -68h-5q-70 0 -70 70q0 69 69 71z" />
+ <glyph glyph-name="afii57407" unicode="&#x61f;" horiz-adv-x="473"
+ d="M147 663q0 50 33.5 83.5t88.5 33.5q67 0 93.5 -35t26.5 -81q0 -36 -14.5 -51.5t-31.5 -15.5t-29 14t-12 28q0 13 16.5 32t16.5 29q0 11 -19.5 28.5t-44.5 17.5q-64 0 -64 -62q0 -28 15 -51t32.5 -39t32.5 -56.5t15 -99.5q0 -28 -3 -63h-25q-1 63 -11 98t-22.5 46
+ t-35.5 33t-40 51q-18 29 -18 60zM344 256q0 -58 -44 -58h-1q-60 0 -60 51q1 51 55 51q50 0 50 -44z" />
+ <glyph glyph-name="afii57409" unicode="&#x621;" horiz-adv-x="350"
+ d="M277 363q-5 0 -18 28t-27 28q-20 0 -40 -35t-20 -59q0 -16 10 -43t24 -27q7 0 14 3.5t16 9.5t33.5 18.5t59.5 26.5l-13 -52q-76 -23 -231 -140q43 60 97 108q-39 10 -55 28t-16 54q0 53 34 98t82 71h8q56 -3 56 -60q0 -17 -3.5 -37t-10.5 -20z" />
+ <glyph glyph-name="afii57410" unicode="&#x622;" horiz-adv-x="321"
+ d="M154 1055q16 0 43 -2t39 -2q34 0 54 9t67 45l-17 -55q-17 -29 -44.5 -40t-85.5 -11q-11 0 -35.5 1t-41.5 1q-15 -1 -26.5 0t-35.5 -12t-59 -43q35 69 59 89t83 20zM149 154q27 331 27 391q0 83 -9 265l42 89q14 -255 14 -418q0 -171 -74 -327z" />
+ <glyph glyph-name="afii57411" unicode="&#x623;" horiz-adv-x="249"
+ d="M209 1044q-4 0 -12 18t-18 18q-13 0 -25.5 -22.5t-12.5 -38.5q0 -11 6 -28t15 -17q5 0 9.5 2t10 6t22 12t38.5 17l-8 -33q-49 -15 -150 -91q26 36 63 70q-26 7 -36 18.5t-10 34.5q0 35 22 64t53 46h5q36 -2 36 -39t-8 -37zM149 154q27 369 27 391q0 85 -9 266l42 89
+ q14 -255 14 -419q0 -171 -74 -327z" />
+ <glyph glyph-name="afii57412" unicode="&#x624;" horiz-adv-x="399"
+ d="M342 652q-4 0 -12 18t-18 18q-13 0 -25.5 -22.5t-12.5 -38.5q0 -11 6 -28t15 -17q5 0 9.5 2t10 6t22 12t38.5 17l-8 -33q-49 -15 -150 -91q26 36 63 70q-26 7 -36 18.5t-10 34.5q0 35 22 64t53 46h5q36 -2 36 -39t-8 -37zM189 303q0 65 32 108t85 43h9q68 -11 84 -172
+ v-85q0 -112 -106 -247q-59 -75 -167 -75h-53v10q119 70 149.5 96.5t75.5 100.5q34 55 34 96q0 14 -2 21h-99q-42 18 -42 88v16zM341 288q-2 52 -10 77t-32 25q-45 0 -45 -102h9q9 0 27.5 -0.5t26.5 -0.5q16 0 24 1z" />
+ <glyph glyph-name="afii57413" unicode="&#x625;" horiz-adv-x="249"
+ d="M212 37q-4 0 -12 18t-18 18q-13 0 -25.5 -22.5t-12.5 -38.5q0 -11 6 -28t15 -17q5 0 9.5 2t10 6t22 12t38.5 17l-8 -33q-49 -15 -150 -91q26 36 63 70q-26 7 -36 18.5t-10 34.5q0 35 22 64t53 46h5q36 -2 36 -39t-8 -37zM149 154q27 369 27 391q0 85 -9 266l42 89
+ q14 -255 14 -419q0 -171 -74 -327z" />
+ <glyph glyph-name="afii57414" unicode="&#x626;" horiz-adv-x="776"
+ d="M447 606q-4 0 -12 18t-18 18q-13 0 -25.5 -22.5t-12.5 -38.5q0 -11 6 -28t15 -17q5 0 9.5 2t10 6t22 12t38.5 17l-8 -33q-49 -15 -150 -91q26 36 63 70q-26 7 -36 18.5t-10 34.5q0 35 22 64t53 46h5q36 -2 36 -39t-8 -37zM714 465q27 0 35.5 -15t8.5 -43q0 -9 -2 -27
+ q-33 26 -66 26q-34 0 -80.5 -43t-46.5 -63q0 -29 80 -29q3 0 19 2t30 2q63 0 63 -37v-4q0 -118 -132 -197q-89 -53 -206 -53q-82 0 -141 17.5t-89 47t-43 60.5t-13 65q0 107 83 222l11 -4q-52 -98 -52 -163t52 -106.5t146 -48.5q302 16 348 109q-2 20 -101 20h-6
+ q-95 0 -95 56q0 65 67 135.5t130 70.5z" />
+ <glyph glyph-name="afii57415" unicode="&#x627;" horiz-adv-x="249"
+ d="M149 154q27 369 27 391q0 85 -9 266l42 89q14 -255 14 -419q0 -171 -74 -327z" />
+ <glyph glyph-name="afii57416" unicode="&#x628;" horiz-adv-x="950"
+ d="M644 2l-52 -54l-52 54l52 53zM926 278q0 82 -10 117t-42 62l18 64q65 -41 65 -124q0 -5 -1 -13t-1 -13v-174h-718q-56 0 -83.5 21t-27.5 76q0 77 70 203l10 -9q-52 -104 -52 -141t42 -69h730z" />
+ <glyph glyph-name="afii57417" unicode="&#x629;" horiz-adv-x="424"
+ d="M392 670l-55 -55l-55 55l55 55zM235 670l-56 -55l-55 55l55 55zM251 564q72 -80 107.5 -145t35.5 -104q0 -21 -8.5 -46t-18.5 -33q-14 -12 -41 -23t-49 -11q-64 0 -93 11.5t-51 49.5q-6 10 -6 34q0 40 30 97.5t50 87.5l-8 10zM235 454q-69 -80 -69 -126q0 -32 32.5 -45
+ t74.5 -13q52 0 69.5 8.5t17.5 26.5q0 28 -31.5 78t-93.5 71z" />
+ <glyph glyph-name="afii57418" unicode="&#x62a;" horiz-adv-x="925"
+ d="M530 574l-65 -66l-67 66l67 67zM740 574l-65 -66l-67 66l67 67zM862 512q63 -39 63 -119q0 -9 -2 -25v-169h-693q-79 0 -96 41q-11 25 -11 53q0 19 5 47q12 59 63 149l9 -8q-32 -62 -49 -125q-1 -4 -1 -12q0 -35 41 -67h704q0 45 -5 95q-6 46 -45 79z" />
+ <glyph glyph-name="afii57419" unicode="&#x62b;" horiz-adv-x="924"
+ d="M756 543l-64 -66l-67 66l67 67zM531 543l-64 -66l-67 66l67 67zM643 665l-65 -67l-66 67l66 66zM921 275q0 64 -8.5 103t-16.5 49.5t-26 25.5l17 63q65 -41 65 -123q0 -5 -1 -13t-1 -13v-173h-713q-55 0 -82.5 21t-27.5 76q0 75 70 201l9 -8q-51 -99 -51 -140
+ q0 -38 42 -69h724z" />
+ <glyph glyph-name="afii57420" unicode="&#x62c;" horiz-adv-x="750"
+ d="M330 491q16 0 111 -16.5t206 -16.5l88 2l-20 -63h-7q-173 0 -292 -51t-193 -158q-54 -76 -54 -157q0 -35 8.5 -67.5t28 -64t58 -50.5t91.5 -19q112 0 296 46l48 -47q-157 -49 -319 -55h-26q-132 14 -178 78q-45 63 -45 82q-7 21 -7 53q0 68 31.5 128.5t93.5 132.5
+ q143 118 237 144q-52 15 -106 27t-108 12q-50 0 -64 -17l-27 -10q47 48 77 67.5t72 19.5zM497 104l-53 -53l-52 53l52 51z" />
+ <glyph glyph-name="afii57421" unicode="&#x62d;" horiz-adv-x="748"
+ d="M330 505q12 0 109.5 -16t209.5 -16l89 1l-20 -62h-7q-175 0 -294.5 -50t-194.5 -156q-54 -75 -54 -155q0 -36 8.5 -68.5t28.5 -63t59 -49t93 -18.5q110 0 307 44l37 -46q-159 -48 -320 -54h-27q-133 14 -180 77q-45 59 -45 82q-7 20 -7 52q0 67 32 126.5t94 131.5
+ q145 118 239 143q-51 14 -108.5 25.5t-109.5 11.5q-50 0 -62 -16l-27 -10q33 33 50 47.5t43.5 26.5t56.5 12z" />
+ <glyph glyph-name="afii57422" unicode="&#x62e;" horiz-adv-x="701"
+ d="M308 503q19 0 107.5 -15.5t193.5 -15.5l84 2l-19 -59h-7q-323 0 -461 -195q-51 -70 -51 -145q0 -32 8 -62t25.5 -60t53 -48.5t84.5 -18.5q105 0 303 59l29 -60q-150 -45 -302 -51h-25q-125 13 -170 72q-42 57 -42 78q-7 18 -7 49q0 62 29 117.5t90 126.5q137 110 225 134
+ q-50 13 -103 24t-102 11q-47 0 -59 -15l-25 -9q31 31 47 45t41 25t53 11zM379 680l-44 -44l-43 44l43 43z" />
+ <glyph glyph-name="afii57423" unicode="&#x62f;" horiz-adv-x="397"
+ d="M382 278q-7 27 -8 45t-7 35t-7.5 27.5t-9.5 22t-14 18.5t-19.5 17.5t-26.5 19l-36 22.5l2 79q22 -7 35.5 -12.5t40 -26t43.5 -48.5t32.5 -80t19.5 -119q0 -78 -56 -78h-202q-55 0 -55 96v21l12 1q4 -38 28 -40h228z" />
+ <glyph glyph-name="afii57424" unicode="&#x630;" horiz-adv-x="399"
+ d="M303 725l-57 -57l-55 57l55 55zM378 277q-6 26 -7 44t-6.5 34.5t-7.5 27t-10 22l-13.5 19t-19 17.5t-27 18.5l-35.5 22.5l2 78q21 -7 35 -13t40 -26t42.5 -47.5t32 -79t19.5 -117.5q0 -77 -55 -77h-200q-54 0 -54 95v20l12 2q4 -38 28 -40h224z" />
+ <glyph glyph-name="afii57425" unicode="&#x631;" horiz-adv-x="328"
+ d="M325 447q20 -69 20 -148q0 -22 -5 -58t-6 -46l-128 -241q-49 -72 -103 -84l-104 -23l5 21q83 49 106 81l69 100q70 99 88 140t18 79q0 45 -18 132z" />
+ <glyph glyph-name="afii57426" unicode="&#x632;" horiz-adv-x="331"
+ d="M326 601l-56 -56l-59 56l59 53zM325 447q20 -69 20 -148q0 -22 -5 -58t-6 -46l-128 -241q-43 -53 -103 -84l-104 -23l5 21q18 14 34 24t39 31.5t46.5 49t57 76t71.5 112.5q33 54 33 107q0 45 -18 132z" />
+ <glyph glyph-name="afii57427" unicode="&#x633;" horiz-adv-x="951"
+ d="M883 274q52 0 52 19q0 26 -40 116l23 36q45 -101 45 -153t-19 -70t-56 -18q-23 0 -31.5 0.5t-25 8t-34.5 23.5q-25 -34 -61 -34q-58 0 -107 -1q0 -45 -8.5 -79.5t-18 -53.5t-32 -35.5t-35.5 -22.5t-43 -18q-63 -25 -152 -25h-33q-34 2 -60.5 8t-57.5 21t-48 47.5
+ t-17 79.5q0 64 82 224l13 -23q-67 -101 -67 -158q0 -70 41 -106t150 -36q63 0 134 21t84 41q30 45 30 122q0 67 -42 116l33 72q32 -56 39 -120h107q40 0 40 68v16l13 7q13 -56 31 -74.5t71 -18.5z" />
+ <glyph glyph-name="afii57428" unicode="&#x634;" horiz-adv-x="949"
+ d="M876 272q49 0 49 19q0 25 -39 114l23 36q44 -99 44 -151q0 -50 -19 -68.5t-55 -18.5q-7 -1 -17 -0.5t-20 2.5t-24 9.5t-29 20.5q-25 -33 -59 -33q-59 0 -107 -1q0 -55 -9 -91.5t-31.5 -58.5t-40 -31.5t-55.5 -24.5q-60 -25 -149 -25h-33q-26 1 -47 4.5t-47.5 13.5
+ t-44 25.5t-30 44t-12.5 66.5q0 63 81 220l13 -23q-67 -102 -67 -156q0 -68 39.5 -103.5t150.5 -35.5q62 0 132 21t83 41q29 44 29 120q0 67 -41 113l33 72q30 -56 38 -118h106q40 0 40 69v13l13 7q12 -54 30 -73t72 -19zM855 553l-47 -45l-49 45l49 45zM774 656l-47 -46
+ l-49 46l49 44zM691 553l-47 -45l-49 45l49 45z" />
+ <glyph glyph-name="afii57429" unicode="&#x635;" horiz-adv-x="949"
+ d="M832 466q20 0 38 -5t37 -18t30 -41t11 -67q0 -33 -7 -67l-15 -34v-1q0 -31 -187 -31l-150 -1q-1 -66 -19.5 -111.5t-53.5 -69.5t-76.5 -33.5t-97.5 -9.5q-212 0 -212 177q4 111 35 197l18 -6q-28 -78 -28 -150q0 -78 40.5 -120t147.5 -44q65 2 111 18.5t68.5 42.5
+ t32 52.5t9.5 56.5q0 71 -63 144l34 72q44 -105 59 -131l120 120q58 55 107 60h11zM895 323q0 82 -84 82q-80 0 -183 -131q7 0 20.5 -0.5t20.5 -0.5q27 0 162 5q64 16 64 45z" />
+ <glyph glyph-name="afii57430" unicode="&#x636;" horiz-adv-x="949"
+ d="M832 466q20 0 38 -5t37 -18t30 -41t11 -67q0 -33 -7 -67l-15 -34v-1q0 -31 -187 -31l-150 -1q-1 -66 -19.5 -111.5t-53.5 -69.5t-76.5 -33.5t-97.5 -9.5q-212 0 -212 177q4 111 35 197l18 -6q-28 -78 -28 -150q0 -78 40.5 -120t147.5 -44q65 2 111 18.5t68.5 42.5
+ t32 52.5t9.5 56.5q0 71 -63 144l34 72q44 -105 59 -131l120 120q58 55 107 60h11zM895 333q0 82 -84 82q-80 0 -183 -131q7 0 20.5 -0.5t20.5 -0.5q27 0 162 5q64 16 64 45zM747 633l-49 -48l-48 48l48 48z" />
+ <glyph glyph-name="afii57431" unicode="&#x637;" horiz-adv-x="557"
+ d="M165 277q21 15 21 39q0 126 -86 384l63 83l26.5 -146.5t26.5 -168t12 -140.5q0 -4 -0.5 -11t-0.5 -10q115 131 218 131q22 0 41 -6t39 -21t31.5 -47t11.5 -78v-4q0 -81 -61 -81h-513l-1 79zM536 304q0 45 -28.5 64.5t-65.5 19.5q-38 0 -86.5 -28t-79.5 -56l-20 -20h279
+ q1 7 1 20z" />
+ <glyph glyph-name="afii57432" unicode="&#x638;" horiz-adv-x="550"
+ d="M443 612l-46 -46l-47 46l47 47zM165 277q21 15 21 39q0 126 -86 384l63 83l26.5 -146.5t26.5 -168t12 -140.5q0 -4 -0.5 -11t-0.5 -10q115 131 218 131q22 0 41 -6t39 -21t31.5 -47t11.5 -78v-4q0 -81 -61 -81h-513l-1 79zM536 304q0 45 -28.5 64.5t-65.5 19.5
+ q-38 0 -86.5 -28t-79.5 -56l-20 -20h279q1 7 1 20z" />
+ <glyph glyph-name="afii57433" unicode="&#x639;" horiz-adv-x="625"
+ d="M130 -67q0 53 31 127t93 126q-87 75 -122 117v29v2q0 62 65 119q56 49 126 49h5q53 -8 121 -50q-13 1 -36 1q-76 0 -153.5 -28t-86.5 -54q2 -37 51 -77.5t95 -40.5q10 0 37.5 14t81 31t121.5 22l-35 -67q-146 -15 -219 -90q-131 -123 -131 -195q0 -76 361 -122h111
+ l-104 -65q-176 8 -265 26t-118 46t-29 80z" />
+ <glyph glyph-name="afii57434" unicode="&#x63a;" horiz-adv-x="602"
+ d="M130 -62q0 60 33 131.5t90 119.5q-87 74 -121 116v29v2q0 62 65 119q55 48 124 48h4q52 -8 121 -49q-10 1 -30 1q-77 0 -156 -28t-88 -54q4 -36 51.5 -76.5t93.5 -40.5h6q119 58 231 66l-35 -66q-143 -15 -216 -89q-129 -122 -129 -194q0 -73 356 -120h110l-103 -65
+ q-173 8 -261 26t-117 45.5t-29 78.5zM323 720l-48 -48l-49 48l49 48z" />
+ <glyph glyph-name="afii57441" unicode="&#x641;" horiz-adv-x="801"
+ d="M592 432q0 59 29.5 121.5t73.5 62.5h4q25 0 49.5 -24t40.5 -71q22 -64 22 -158v-66q0 -92 -86 -92l-526 1q-43 5 -56.5 28.5t-14.5 98.5q2 54 26 130l26 -27q-34 -78 -34 -114q0 -34 34 -41q50 0 150 -0.5t149 -0.5q33 0 99 0.5t99 0.5h3q85 0 85 48v5q-56 13 -94.5 20.5
+ t-58.5 25.5t-20 52zM693 529q-36 -10 -36 -71q0 -49 85 -49q15 0 22 1v1q-8 39 -27.5 76t-43.5 42zM675 712l-49 -50l-50 50l50 51z" />
+ <glyph glyph-name="afii57442" unicode="&#x642;" horiz-adv-x="696"
+ d="M709 562l-55 -55l-55 55l55 55zM552 562l-56 -55l-55 55l55 55zM719 183q-17 -140 -88 -187q-95 -56 -259 -56h-31q-209 45 -209 163q-2 22 -2 35q0 96 51 218h11q-28 -97 -28 -167q0 -28 4 -47q11 -116 273 -116h13q96 16 152 36q75 38 75 111q0 10 -1 16q-2 18 -31 18
+ q-21 0 -49 -7q-95 0 -95 51q0 4 2 14q2 37 30 86q29 59 69 66q52 -24 85 -77q25 -51 28 -94v-63zM607 354h-3q-33 0 -48 -44q-6 -10 -6 -18q0 -20 41 -20h9q38 0 44 2q6 0 6 10q0 2 -2 10q-3 16 -17 37z" />
+ <glyph glyph-name="afii57443" unicode="&#x643;" horiz-adv-x="757"
+ d="M948 958l-199 -87q-19 -8 -73.5 -33.5t-54.5 -32.5q0 -10 107 -126l40 -51t31 -41.5t24.5 -38.5t21.5 -43t21 -55.5l24 -74.5q4 -39 4 -75q0 -101 -42 -101h-1l-587 2q-78 0 -128 87q-15 25 -15 89q0 67 20 131l8 -4q-7 -45 -7 -85q0 -77 39.5 -111t137.5 -34h11h529
+ q2 24 2 35q0 121 -125 286l-61 65l-11 -14q-34 23 -86 75q-4 26 -4 38q0 60 45.5 102t171.5 94l163 66z" />
+ <glyph glyph-name="afii57444" unicode="&#x644;" horiz-adv-x="655"
+ d="M377 -150q-45 0 -83 7.5t-77.5 27t-62 60t-22.5 98.5q0 102 61 261l16 -6q-46 -141 -46 -216q0 -74 76 -126q88 -19 160 -19q82 0 117 18q89 46 89 157q0 264 -37 704l38 38l52 41l47 -146l-52 -64v-52q0 -169 6 -305t6 -167q0 -83 -11.5 -137t-42 -95.5t-88 -60
+ t-146.5 -18.5z" />
+ <glyph glyph-name="afii57445" unicode="&#x645;" horiz-adv-x="549"
+ d="M280 303q-28 0 -51 -38q-4 16 -4 33q0 66 80 68h27q28 0 81.5 -17.5t103.5 -52.5t50 -74q0 -26 -28 -57t-63 -31l-72 24q-71 24 -120 24q-60 0 -85 -36q30 -234 30 -373q0 -63 -22 -111q-20 126 -36 206t-22.5 100t-11 52.5t-8.5 96.5v11q0 50 42 95.5t107 45.5
+ q25 0 130 -28q-25 17 -68 39.5t-60 22.5z" />
+ <glyph glyph-name="afii57446" unicode="&#x646;" horiz-adv-x="651"
+ d="M441 451l-59 -55l-58 55l58 55zM362 -20q67 0 112.5 7t84.5 26.5t58 58t19 97.5q-1 156 -41 188l58 96q17 -71 20 -243l-7 -78q-5 -70 -26 -117t-57 -70.5t-76 -32.5t-96 -9q-32 0 -49 1q-136 0 -188.5 53t-52.5 156q0 92 28 189l21 -4q-17 -74 -17 -132q0 -6 1 -18.5
+ t1 -18.5q0 -147 207 -149z" />
+ <glyph glyph-name="afii57470" unicode="&#x647;" horiz-adv-x="424"
+ d="M251 564q72 -80 107.5 -145t35.5 -104q0 -21 -8.5 -46t-18.5 -33q-14 -12 -41 -23t-49 -11q-64 0 -93 11.5t-51 49.5q-6 10 -6 34q0 40 30 97.5t50 87.5l-8 10zM235 454q-69 -80 -69 -126q0 -32 32.5 -45t74.5 -13q52 0 69.5 8.5t17.5 26.5q0 28 -31.5 78t-93.5 71z" />
+ <glyph glyph-name="afii57448" unicode="&#x648;" horiz-adv-x="399"
+ d="M189 303q0 65 32 108t85 43h9q68 -11 84 -172v-85q0 -112 -106 -247q-59 -75 -167 -75h-53v10q119 70 149.5 96.5t75.5 100.5q34 55 34 96q0 14 -2 21h-99q-42 18 -42 88v16zM341 288q-2 52 -10 77t-32 25q-45 0 -45 -102h9q9 0 27.5 -0.5t26.5 -0.5q16 0 24 1z" />
+ <glyph glyph-name="afii57449" unicode="&#x649;" horiz-adv-x="776"
+ d="M714 465q27 0 35.5 -15t8.5 -43q0 -9 -2 -27q-33 26 -66 26q-34 0 -80.5 -43t-46.5 -63q0 -29 80 -29q3 0 19 2t30 2q63 0 63 -37v-4q0 -118 -132 -197q-89 -53 -206 -53q-82 0 -141 17.5t-89 47t-43 60.5t-13 65q0 107 83 222l11 -4q-52 -98 -52 -163t52 -106.5
+ t146 -48.5q302 16 348 109q-2 20 -101 20h-6q-95 0 -95 56q0 65 67 135.5t130 70.5z" />
+ <glyph glyph-name="afii57450" unicode="&#x64a;" horiz-adv-x="776"
+ d="M461 -122l-65 -66l-67 66l67 67zM619 -89l-65 -66l-67 66l67 67zM714 465q27 0 35.5 -15t8.5 -43q0 -9 -2 -27q-33 26 -66 26q-34 0 -80.5 -43t-46.5 -63q0 -29 80 -29q3 0 19 2t30 2q63 0 63 -37v-4q0 -118 -132 -197q-89 -53 -206 -53q-82 0 -141 17.5t-89 47t-43 60.5
+ t-13 65q0 107 83 222l11 -4q-52 -98 -52 -163t52 -106.5t146 -48.5q302 16 348 109q-2 20 -101 20h-6q-95 0 -95 56q0 65 67 135.5t130 70.5z" />
+ <glyph glyph-name="afii57451" unicode="&#x64b;" horiz-adv-x="300"
+ d="M190 1006l-78 -37.5t-42 -28.5t-16 -36l151 74q23 10 32 22t12 35zM190 916l-78 -37.5t-42 -28.5t-16 -36l151 74q23 10 32 22t12 35z" />
+ <glyph glyph-name="afii57453" unicode="&#x64d;" horiz-adv-x="300"
+ d="M180 -153l-74.5 -37t-43.5 -29t-18 -37l151 74q23 10 32 22t12 35zM180 -63l-74.5 -37t-43.5 -29t-18 -37l151 74q23 10 32 22t12 35z" />
+ <glyph glyph-name="afii57454" unicode="&#x64e;" horiz-adv-x="300"
+ d="M190 1006l-78 -37.5t-42 -28.5t-16 -36l151 74q23 10 32 22t12 35z" />
+ <glyph glyph-name="afii57455" unicode="&#x64f;" horiz-adv-x="300"
+ d="M219 1010q24 -11 30 -17.5t6 -15.5q0 -11 -6 -25l-50 23q-34 -64 -127 -100h-21q71 39 124 112l-21 17t-15 13.5t-9 14.5t-3 18q0 34 25.5 59t51.5 25q31 0 31 -41q0 -30 -16 -83zM201 1052q0 18 -5.5 25t-21.5 7q-13 0 -13 -17q0 -12 39 -41q1 10 1 26z" />
+ <glyph glyph-name="afii57456" unicode="&#x650;" horiz-adv-x="300"
+ d="M180 -153l-74.5 -37t-43.5 -29t-18 -37l151 74q23 10 32 22t12 35z" />
+ <glyph glyph-name="afii57457" unicode="&#x651;" horiz-adv-x="300"
+ d="M250 1011q-1 -13 -15 -30.5t-35 -17.5q-8 0 -17 3q-18 -45 -51 -45q-19 0 -31.5 15.5t-12.5 39.5q0 14 5 37h7q-5 -18 -5 -28q0 -15 8.5 -24t20.5 -9q13 0 22.5 11t27.5 42q10 -14 22 -14q11 0 23 13t12 25q0 21 -23 35l6 12q36 -50 36 -65z" />
+ <glyph glyph-name="afii57392" unicode="&#x660;" horiz-adv-x="297"
+ d="M331 404l-111 -124l-106 125l106 122z" />
+ <glyph glyph-name="afii57393" unicode="&#x661;" horiz-adv-x="254"
+ d="M210 796q79 -141 101.5 -271.5t22.5 -347.5q-6 -22 -15 -22q-11 0 -20.5 60t-20 141t-41.5 181.5t-77 165.5z" />
+ <glyph glyph-name="afii57394" unicode="&#x662;" horiz-adv-x="427"
+ d="M300 705q22 0 38.5 3.5t28 13.5l18.5 16.5t13 25.5l8 25.5t7 30.5l34 -38q0 -97 -22 -131.5t-97 -34.5q-51 0 -83 23q27 -126 39 -438q-14 -29 -26 -29q-19 0 -29 58.5t-16 138.5t-34.5 180t-78.5 166l60 94q48 -68 72 -86t68 -18z" />
+ <glyph glyph-name="afii57395" unicode="&#x663;" horiz-adv-x="497"
+ d="M144 824l42.5 -54t32 -40.5t22.5 -18t32 -8.5q44 0 57.5 19t20.5 69q7 15 14 15q11 0 16.5 -29.5t12.5 -42.5q9 -19 41 -19q49 0 49 49v5q3 6 11 19t10 13q4 0 13 -49q0 -120 -77 -125q-60 7 -76 52q-30 -38 -46 -48t-46 -10q-8 0 -32 2q23 -95 23 -209q0 -231 -39 -231
+ q-12 0 -27 29q5 97 5 156q-1 29 0 54t-3.5 59t-13.5 70.5t-31 89.5t-54 116z" />
+ <glyph glyph-name="afii57396" unicode="&#x664;" horiz-adv-x="440"
+ d="M353 675q37 0 56.5 5t20.5 5q3 0 3 -4q0 -5 -11 -27q-17 -28 -43.5 -37.5t-98.5 -9.5h-48h-20q13 -62 13 -169q0 -260 -29 -260q-15 0 -18 16q-7 213 -23.5 294.5t-81.5 213.5l46 95l48 -67q7 -19 13 -19q2 0 7 22t14 48t36.5 48t68.5 22q24 0 58 -17t34 -49
+ q0 -12 -14 -12q-28 27 -58 27q-12 0 -28 -3.5t-33.5 -16.5t-17.5 -34q0 -16 7 -36q28 -22 47.5 -28.5t51.5 -6.5z" />
+ <glyph glyph-name="afii57397" unicode="&#x665;" horiz-adv-x="465"
+ d="M145 189q-59 0 -79 36.5t-20 107.5q0 16 42 115q39 98 143 239l-21 29l52 57q87 -128 127 -213.5t43 -188.5v-11q0 -73 -29.5 -121.5t-87.5 -48.5q-60 0 -84 60q-25 -53 -86 -61zM257 661q-69 -98 -117.5 -190.5t-48.5 -140.5q0 -81 55 -81q12 0 21.5 8t21.5 23.5
+ t23 23.5q13 11 40 -16t47 -27q12 0 30 6.5t36.5 28t18.5 53.5q0 50 -34 141t-93 171z" />
+ <glyph glyph-name="afii57398" unicode="&#x666;" horiz-adv-x="466"
+ d="M247 559q27 0 43 5t27.5 13t49.5 26t95 37q3 -45 3 -76q-84 -28 -196.5 -152.5t-179.5 -271.5q-2 -1 -4 -1q-6 0 -6 9q0 46 45.5 155t108.5 185q-86 13 -119.5 42t-33.5 54q0 50 58.5 113t110.5 65h5q36 0 57.5 -14.5t42.5 -48.5q1 -1 1 -3q0 -4 -9 -4q-8 0 -31.5 4.5
+ t-39.5 4.5q-46 0 -79.5 -33t-33.5 -54q0 -22 19.5 -38.5t65.5 -16.5z" />
+ <glyph glyph-name="afii57399" unicode="&#x667;" horiz-adv-x="421"
+ d="M212 268q0 65 -57.5 217t-107.5 198l25 91q113 -148 175 -429q21 283 118 428l23 -90q-31 -45 -67 -161.5t-40 -225.5l-5 -45q-5 -47 -39 -47v-1q-26 12 -26 48q0 2 0.5 8t0.5 9z" />
+ <glyph glyph-name="afii57400" unicode="&#x668;" horiz-adv-x="459"
+ d="M314 592q54 -206 121 -293l-36 -100l-154 441l-151 -441l-38 97q67 86 121 294t68 219q17 -11 69 -217z" />
+ <glyph glyph-name="afii57401" unicode="&#x669;" horiz-adv-x="424"
+ d="M398 165q-133 121 -133 344q0 34 1 53q-51 -9 -88 -9q-55 0 -78 26t-23 60q0 13 3.5 32.5t13 46t24 49t39.5 38t56 15.5q49 0 79.5 -65t35.5 -176q-2 -16 -2 -46q0 -76 23.5 -136t71.5 -122zM142 677q0 -29 19.5 -38t61.5 -9q29 0 47 1q-4 24 -7.5 38.5t-11 31.5t-21 25
+ t-32.5 8q-23 0 -39.5 -19.5t-16.5 -37.5z" />
+ <glyph glyph-name="uni066B" unicode="&#x66b;" horiz-adv-x="212"
+ d="M79 183q-24 0 -39.5 23t-15.5 44q0 25 19.5 41t46.5 16q31 0 48.5 -28t17.5 -67q0 -25 -13 -53.5t-36 -47.5l-15 -3q29 48 36 91q-37 -16 -49 -16z" />
+ <glyph glyph-name="uni0674" unicode="&#x674;" horiz-adv-x="300"
+ d="M203 970q-4 0 -12 18t-18 18q-13 0 -25.5 -22.5t-12.5 -38.5q0 -11 6 -28t15 -17q5 0 9.5 2t10 6t22 12t38.5 17l-8 -33q-49 -15 -150 -91q26 36 63 70q-26 7 -36 18.5t-10 34.5q0 35 22 64t53 46h5q36 -2 36 -39t-8 -37z" />
+ <glyph glyph-name="afii57506" unicode="&#x67e;" horiz-adv-x="926"
+ d="M508 26l-52 -55l-53 55l53 52zM921 277q0 51 -4 84.5t-14.5 53t-15 25t-19.5 18.5l18 64q66 -40 66 -125q0 -5 -1 -13t-1 -13v-176h-724q-55 0 -83.5 21.5t-28.5 76.5q0 79 71 204l10 -8q-52 -101 -52 -143q0 -38 42 -69h736zM600 -83l-52 -55l-53 55l53 52zM693 26
+ l-53 -55l-53 55l53 52z" />
+ <glyph glyph-name="afii57507" unicode="&#x686;" horiz-adv-x="750"
+ d="M673 112l-62 -63l-63 63l63 61zM473 112l-62 -63l-63 63l63 61zM580 -13l-62 -61l-63 61l63 62zM334 506q13 0 111 -16.5t212 -16.5l90 2l-20 -63h-7q-177 0 -298 -51t-198 -158q-54 -77 -54 -156q0 -35 8.5 -67.5t28 -64.5t59 -51t94.5 -19q114 0 313 45l37 -47
+ q-162 -50 -325 -54h-27q-134 13 -182 77q-45 61 -45 83q-8 22 -8 53q0 67 32.5 127.5t95.5 133.5q145 118 242 144q-54 15 -109.5 27t-109.5 12q-51 0 -65 -17l-27 -10q34 34 51 48.5t43.5 26.5t57.5 12z" />
+ <glyph glyph-name="afii57508" unicode="&#x698;" horiz-adv-x="338"
+ d="M363 587l-52 -50l-53 50l53 49zM285 707l-52 -50l-54 50l54 48zM216 587l-52 -50l-53 50l53 49zM325 447q20 -69 20 -148q0 -22 -5 -58t-6 -46l-128 -241q-49 -72 -103 -84l-104 -23l5 21q18 14 34 24t39 31.5t46.5 49t57 76t71.5 112.5q33 54 33 107q0 45 -18 132z" />
+ <glyph glyph-name="afii57509" unicode="&#x6af;" horiz-adv-x="874"
+ d="M948 962l-199 -87q-19 -8 -73.5 -33.5t-54.5 -32.5q0 -10 107 -126l40 -51t31 -41.5t24.5 -38.5t21.5 -43t21 -55.5l24 -74.5q4 -39 4 -75q0 -101 -42 -101h-1l-587 2q-78 0 -128 87q-15 26 -15 89q0 67 20 131l8 -5q-7 -45 -7 -84q0 -77 39.5 -111t137.5 -34h11h529
+ q2 24 2 35q0 121 -125 286l-61 65l-11 -14q-34 23 -86 75q-4 26 -4 38q0 60 45.5 102t171.5 94l163 66zM870 1115v-52l-304 -135q21 45 304 187z" />
+ <glyph glyph-name="uni06CC" unicode="&#x6cc;" horiz-adv-x="776"
+ d="M714 465q27 0 35.5 -15t8.5 -43q0 -9 -2 -27q-33 26 -66 26q-34 0 -80.5 -43t-46.5 -63q0 -29 80 -29q3 0 19 2t30 2q63 0 63 -37v-4q0 -118 -132 -197q-89 -53 -206 -53q-82 0 -141 17.5t-89 47t-43 60.5t-13 65q0 107 83 222l11 -4q-52 -98 -52 -163t52 -106.5
+ t146 -48.5q302 16 348 109q-2 20 -101 20h-6q-95 0 -95 56q0 65 67 135.5t130 70.5z" />
+ <glyph glyph-name="uni06D4" unicode="&#x6d4;" horiz-adv-x="176"
+ d="M90 238q10 37 48 46q38 -9 48 -46q-10 -38 -48 -48q-38 10 -48 48z" />
+
+ <!-- presentational forms -->
+ <glyph glyph-name="uniFB56" unicode="&#x67e;" horiz-adv-x="926" arabic-form="isolated"
+d="M508 26l-52 -55l-53 55l53 52zM921 277c0 34 -1.33331 62.1667 -4 84.5s-7.5 40 -14.5 53s-12 21.3333 -15 25s-9.5 9.83334 -19.5 18.5l18 64c44 -26.6667 66 -68.3333 66 -125c0 -3.33334 -0.333313 -7.66666 -1 -13s-1 -9.66666 -1 -13v-176h-724
+c-36.6667 0 -64.5 7.16667 -83.5 21.5s-28.5 39.8333 -28.5 76.5c0 52.6667 23.6667 120.667 71 204l10 -8c-34.6667 -67.3333 -52 -115 -52 -143c0 -25.3333 14 -48.3333 42 -69h736zM600 -83l-52 -55l-53 55l53 52zM693 26l-53 -55l-53 55l53 52z" />
+ <glyph glyph-name="uniFB57" unicode="&#x67e;" horiz-adv-x="926" arabic-form="terminal"
+ d="M508 26l-52 -55l-53 55l53 52zM921 277c0 34 -1.33331 62.1667 -4 84.5s-7.5 40 -14.5 53s-12 21.3333 -15 25s-9.5 9.83334 -19.5 18.5l18 64c44 -26.6667 66 -68.3333 66 -125c0 -3.33334 -0.333313 -7.66666 -1 -13s-1 -9.66666 -1 -13v-176h-724
+c-36.6667 0 -64.5 7.16667 -83.5 21.5s-28.5 39.8333 -28.5 76.5c0 52.6667 23.6667 120.667 71 204l10 -8c-34.6667 -67.3333 -52 -115 -52 -143c0 -25.3333 14 -48.3333 42 -69h736zM600 -83l-52 -55l-53 55l53 52zM693 26l-53 -55l-53 55l53 52z" />
+ <glyph glyph-name="uniFB58" unicode="&#x67e;" horiz-adv-x="308" arabic-form="initial"
+ d="M148 58l-57 -58l-58 58l58 58zM207 -73l-57 -59l-57 59l57 58zM268 58l-57 -58l-58 58l58 58zM256 534c30 -43.3333 45 -93 45 -149v-74c0 -73.3333 -17.3333 -110.333 -52 -111h-252l-9 83h280v11c0 68 -18.6667 120.667 -56 158z" />
+ <glyph glyph-name="uniFB59" unicode="&#x67e;" horiz-adv-x="308" arabic-form="medial"
+ d="M148 58l-57 -58l-58 58l58 58zM207 -73l-57 -59l-57 59l57 58zM268 58l-57 -58l-58 58l58 58zM256 534c30 -43.3333 45 -93 45 -149v-74c0 -73.3333 -17.3333 -110.333 -52 -111h-252l-9 83h280v11c0 68 -18.6667 120.667 -56 158z" />
+ <glyph glyph-name="uniFB7A" unicode="&#x686;" horiz-adv-x="750" arabic-form="isolated"
+ d="M673 112l-62 -63l-63 63l63 61zM473 112l-62 -63l-63 63l63 61zM580 -13l-62 -61l-63 61l63 62zM334 506c9.33334 0 46.5 -5.5 111.5 -16.5s135.5 -16.5 211.5 -16.5l90 2l-20 -63h-7c-230.667 0 -396 -69.6667 -496 -209c-36 -51.3333 -54 -103.333 -54 -156
+c0 -23.3333 2.83333 -45.8333 8.5 -67.5c5.66667 -21.6667 15 -43.1667 28 -64.5c13 -21.3333 32.6667 -38.3333 59 -51c26.3333 -12.6667 57.8333 -19 94.5 -19c76 0 180.333 15 313 45l37 -47c-108 -33.3333 -216.333 -51.3333 -325 -54h-27
+c-89.3333 8.66667 -150 34.3333 -182 77c-30 40.6667 -45 68.3333 -45 83c-5.33334 14.6667 -8 32.3333 -8 53c0 44.6667 10.8333 87.1667 32.5 127.5c21.6667 40.3333 53.5 84.8333 95.5 133.5c96.6667 78.6667 177.333 126.667 242 144c-36 10 -72.5 19 -109.5 27
+s-73.5 12 -109.5 12c-34 0 -55.6667 -5.66666 -65 -17l-27 -10c22.6667 22.6667 39.6667 38.8333 51 48.5s25.8333 18.5 43.5 26.5s36.8333 12 57.5 12z" />
+ <glyph glyph-name="uniFB7B" unicode="&#x686;" horiz-adv-x="750" arabic-form="terminal"
+ d="M490 32l-52 -52l-51 52l51 51zM628 401c6 -54.6667 13.3333 -89.3333 22 -104s27.3333 -22 56 -22h50l-3 -81h-40c-20.6667 2 -37.6667 8.83333 -51 20.5s-22.8333 28 -28.5 49s-9.33331 39.5 -11 55.5s-2.5 36.3333 -2.5 61zM333 501c11.3333 0 50 -5.5 116 -16.5
+s134 -16.5 204 -16.5l89 2l-20 -62h-7c-228.667 0 -392.333 -69 -491 -207c-35.3333 -50.6667 -53 -102.333 -53 -155c0 -17.3333 1.33333 -34.1667 4 -50.5c2.66667 -16.3333 8.16667 -33.8333 16.5 -52.5c8.33333 -18.6667 19.3333 -34.8333 33 -48.5s32.5 -25 56.5 -34
+s52 -13.5 84 -13.5c73.3333 0 164.333 11.3333 273 34l67 -36c-107.333 -32 -214.333 -50 -321 -54h-27c-90 9.33333 -150 35 -180 77c-30 40.6667 -45 68 -45 82c-4.66666 13.3333 -7 30.6667 -7 52c0 44.6667 10.6667 87 32 127s52.6667 84 94 132
+c95.3333 77.3333 175 124.667 239 142c-34 9.33334 -70 18 -108 26s-74.3333 12 -109 12c-34 0 -55 -5.33334 -63 -16l-27 -10c32 32 57.8333 54.3333 77.5 67c19.6667 12.6667 43.8333 19 72.5 19zM575 131l-52 -52l-51 52l51 51zM419 131l-52 -52l-51 52l51 51z" />
+ <glyph glyph-name="uniFB7C" unicode="&#x686;" horiz-adv-x="580" arabic-form="initial"
+ d="M271 59l-50 -51l-52 51l52 51zM445 59l-52 -51l-50 51l50 51zM358 -38l-51 -52l-51 52l51 51zM149 354c10.6667 14.6667 21.3333 28.5 32 41.5s20.6667 24.3333 30 34s19.6667 17.3333 31 23s23.3333 8.5 36 8.5c18.6667 0 46.5 -12.8333 83.5 -38.5
+s76.1667 -57.5 117.5 -95.5c20 -23.3333 63 -40.3333 129 -51l2 -76h-590c-15.3333 0 -23 25 -23 75l462 1l-127 90c-15.3333 10.6667 -32 16 -50 16c-22 0 -61 -10.3333 -117 -31z" />
+ <glyph glyph-name="uniFB7D" unicode="&#x686;" horiz-adv-x="580" arabic-form="medial"
+ d="M271 59l-50 -51l-52 51l52 51zM445 59l-52 -51l-50 51l50 51zM358 -38l-51 -52l-51 52l51 51zM149 354c10.6667 14.6667 21.3333 28.5 32 41.5s20.6667 24.3333 30 34s19.6667 17.3333 31 23s23.3333 8.5 36 8.5c18.6667 0 46.5 -12.8333 83.5 -38.5
+s76.1667 -57.5 117.5 -95.5c20 -23.3333 63 -40.3333 129 -51l2 -76h-590c-15.3333 0 -23 25 -23 75l462 1l-127 90c-15.3333 10.6667 -32 16 -50 16c-22 0 -61 -10.3333 -117 -31z" />
+ <glyph glyph-name="uniFB8A" unicode="&#x698;" horiz-adv-x="338" arabic-form="isolated"
+ d="M363 587l-52 -50l-53 50l53 49zM285 707l-52 -50l-54 50l54 48zM216 587l-52 -50l-53 50l53 49zM325 447c13.3333 -46 20 -95.3333 20 -148c0 -11.3333 -0.333344 -19.6667 -1 -25l-10 -79l-128 -241c-32.6667 -48 -67 -76 -103 -84l-104 -23l5 21
+c12.6667 10 24.6667 18.5 36 25.5c11.3333 7 24.3333 17.6667 39 32c14.6667 14.3333 30 30.6667 46 49c16 18.3333 34.8333 43.5 56.5 75.5s45.1667 69 70.5 111c22 36 33 71.6667 33 107c0 30 -6 74 -18 132z" />
+ <glyph glyph-name="uniFB8B" unicode="&#x698;" horiz-adv-x="338" arabic-form="terminal"
+ d="M363 587l-52 -50l-53 50l53 49zM285 707l-52 -50l-54 50l54 48zM216 587l-52 -50l-53 50l53 49zM325 447c13.3333 -46 20 -95.3333 20 -148c0 -11.3333 -0.333344 -19.6667 -1 -25l-10 -79l-128 -241c-32.6667 -48 -67 -76 -103 -84l-104 -23l5 21
+c12.6667 10 24.6667 18.5 36 25.5c11.3333 7 24.3333 17.6667 39 32c14.6667 14.3333 30 30.6667 46 49c16 18.3333 34.8333 43.5 56.5 75.5s45.1667 69 70.5 111c22 36 33 71.6667 33 107c0 30 -6 74 -18 132z" />
+ <glyph glyph-name="uniFB92" unicode="&#x6af;" horiz-adv-x="874" arabic-form="isolated"
+ d="M142 426c0 -50 12.1667 -87.1667 36.5 -111.5s71.8333 -36.5 142.5 -36.5h9h529c1.33331 16 2 27.6667 2 35c0 80.6667 -41.6667 176 -125 286l-61 65l-11 -14c-20 13.3333 -39.6667 29.6667 -59 49l-27 26c-2.66669 17.3333 -4 30 -4 38c0 40 15.1667 74 45.5 102
+s87.5 59.3333 171.5 94l163 66l-6 -63l-199 -87c-12.6667 -5.33331 -37.1667 -16.5 -73.5 -33.5s-54.5 -27.8333 -54.5 -32.5c0 -6.66669 35.6667 -48.6667 107 -126l40 -51c11.3333 -14 21.6667 -27.8333 31 -41.5s17.5 -26.5 24.5 -38.5s14.1667 -26.3333 21.5 -43
+c7.33331 -16.6667 14.3333 -35.1667 21 -55.5l24 -74.5c2.66669 -26 4 -51 4 -75c0 -67.3333 -14 -101 -42 -101h-1l-587 2c-52 0 -94.6667 29 -128 87c-10 17.3333 -15 47 -15 89c0 44.6667 6.66666 88.3333 20 131l8 -5c-4.66667 -35.3333 -7 -62.3333 -7 -81zM870 1115
+v-52l-304 -135c14 30 115.333 92.3333 304 187z" />
+ <glyph glyph-name="uniFB93" unicode="&#x6af;" horiz-adv-x="874" arabic-form="terminal"
+ d="M142 426c0 -50 12.1667 -87.1667 36.5 -111.5s71.8333 -36.5 142.5 -36.5h9h529c1.33331 16 2 27.6667 2 35c0 80.6667 -41.6667 176 -125 286l-61 65l-11 -14c-20 13.3333 -39.6667 29.6667 -59 49l-27 26c-2.66669 17.3333 -4 30 -4 38c0 40 15.1667 74 45.5 102
+s87.5 59.3333 171.5 94l163 66l-6 -63l-199 -87c-12.6667 -5.33331 -37.1667 -16.5 -73.5 -33.5s-54.5 -27.8333 -54.5 -32.5c0 -6.66669 35.6667 -48.6667 107 -126l40 -51c11.3333 -14 21.6667 -27.8333 31 -41.5s17.5 -26.5 24.5 -38.5s14.1667 -26.3333 21.5 -43
+c7.33331 -16.6667 14.3333 -35.1667 21 -55.5l24 -74.5c2.66669 -26 4 -51 4 -75c0 -67.3333 -14 -101 -42 -101h-1l-587 2c-52 0 -94.6667 29 -128 87c-10 17.3333 -15 47 -15 89c0 44.6667 6.66666 88.3333 20 131l8 -5c-4.66667 -35.3333 -7 -62.3333 -7 -81zM870 1115
+v-52l-304 -135c14 30 115.333 92.3333 304 187z" />
+ <glyph glyph-name="uniFB94" unicode="&#x6af;" horiz-adv-x="329" arabic-form="initial"
+ d="M398 912l-199 -82c-85.3333 -36 -128 -56.6667 -128 -62s35.6667 -44.6667 107 -118l40 -47.5c11.3333 -13 21.6667 -25.8333 31 -38.5c9.33334 -12.6667 17.5 -24.6667 24.5 -36s14 -25 21 -41s14 -33.5 21 -52.5s15.1667 -42.5 24.5 -70.5
+c2.66666 -24 4 -47.6667 4 -71c0 -62.6667 -14 -94 -42 -94h-1l-306 2l6 78h308c1.33334 13.3333 2 23 2 29c0 72.6667 -41.6667 160.333 -125 263l-61 61l-11 -13c-16.6667 10 -36.3333 25.3333 -59 46l-27 24c-2.66667 17.3333 -4 29.3333 -4 36
+c0 38.6667 15.8333 71.1667 47.5 97.5c31.6667 26.3333 88.1667 55.1667 169.5 86.5l163 62zM354 1077v-50l-304 -130c14 29.3333 115.333 89.3333 304 180z" />
+ <glyph glyph-name="uniFB95" unicode="&#x6af;" horiz-adv-x="329" arabic-form="medial"
+ d="M398 912l-199 -82c-85.3333 -36 -128 -56.6667 -128 -62s35.6667 -44.6667 107 -118l40 -47.5c11.3333 -13 21.6667 -25.8333 31 -38.5c9.33334 -12.6667 17.5 -24.6667 24.5 -36s14 -25 21 -41s14 -33.5 21 -52.5s15.1667 -42.5 24.5 -70.5
+c2.66666 -24 4 -47.6667 4 -71c0 -62.6667 -14 -94 -42 -94h-1l-306 2l6 78h308c1.33334 13.3333 2 23 2 29c0 72.6667 -41.6667 160.333 -125 263l-61 61l-11 -13c-16.6667 10 -36.3333 25.3333 -59 46l-27 24c-2.66667 17.3333 -4 29.3333 -4 36
+c0 38.6667 15.8333 71.1667 47.5 97.5c31.6667 26.3333 88.1667 55.1667 169.5 86.5l163 62zM354 1077v-50l-304 -130c14 29.3333 115.333 89.3333 304 180z" />
+ <glyph glyph-name="uniFBFC" unicode="&#x6cc;" horiz-adv-x="776" arabic-form="isolated"
+ d="M714 465c18 0 29.8333 -5 35.5 -15s8.5 -24.3333 8.5 -43c0 -2 -0.166687 -4.66666 -0.5 -8s-0.5 -5.66666 -0.5 -7l-1 -12c-22 17.3333 -44 26 -66 26c-22.6667 0 -49.5 -14.3333 -80.5 -43s-46.5 -49.6667 -46.5 -63c0 -19.3333 26.6667 -29 80 -29
+c2 0 8.33331 0.666656 19 2s20.6667 2 30 2c42 0 63 -12.3333 63 -37v-4c0 -78.6667 -44 -144.333 -132 -197c-59.3333 -35.3333 -128 -53 -206 -53c-54.6667 0 -101.667 5.83333 -141 17.5c-39.3333 11.6667 -69 27.3333 -89 47c-20 19.6667 -34.3333 39.8333 -43 60.5
+c-8.66667 20.6667 -13 42.3333 -13 65c0 71.3333 27.6667 145.333 83 222l11 -4c-34.6667 -65.3333 -52 -119.667 -52 -163c0 -43.3333 17.3333 -78.8333 52 -106.5c34.6667 -27.6667 83.3333 -43.8333 146 -48.5c201.333 10.6667 317.333 47 348 109
+c-1.33331 13.3333 -35 20 -101 20h-6c-63.3333 0 -95 18.6667 -95 56c0 43.3333 22.3333 88.5 67 135.5s88 70.5 130 70.5z" />
+ <glyph glyph-name="uniFBFD" unicode="&#x6cc;" horiz-adv-x="700" arabic-form="terminal"
+ d="M370 -14c70 0 130.167 8 180.5 24c50.3333 16 75.5 32.3333 75.5 49v2c0 10 -9 15 -27 15c-1.33331 0 -3.83331 -0.166664 -7.5 -0.5s-6.5 -0.5 -8.5 -0.5h-110c-28 4 -42 20.3333 -42 49c0 2 0.333344 5.16667 1 9.5s1 7.83333 1 10.5c0 38.6667 28 74.6667 84 108
+c30 18 81.3333 27 154 27h50l-1 -77c-8.66669 0 -20.6667 0.166672 -36 0.5s-26.3333 0.5 -33 0.5c-74 0 -123.667 -3.83333 -149 -11.5c-25.3333 -7.66667 -38 -23.1667 -38 -46.5c0 -9.33333 6.33334 -14 19 -14h111c51.3333 0 77 -16.3333 77 -49
+c0 -42.6667 -19 -78 -57 -106s-91 -46.6667 -159 -56c-9.33334 -1.33334 -42.3333 -2 -99 -2c-88 8 -147.167 22.8333 -177.5 44.5c-30.3333 21.6667 -45.8333 56.5 -46.5 104.5v13c0 66 18.3333 135.333 55 208l7 -4c-28 -57.3333 -42 -104.333 -42 -141
+c0 -47.3333 10.6667 -84 32 -110c44.6667 -31.3333 106.667 -47 186 -47z" />
+ <glyph glyph-name="uniFBFE" unicode="&#x6cc;" horiz-adv-x="304" arabic-form="initial"
+ d="M173 55l-59 -57l-61 57l61 57zM300 55l-59 -57l-61 57l61 57zM286 514c30 -41.3333 45 -88 45 -140v-69c0 -69.3333 -17.3333 -104.333 -52 -105h-252c-32.6667 0 -49 26 -49 78h320v10c0 64 -18.6667 113.667 -56 149z" />
+ <glyph glyph-name="uniFBFF" unicode="&#x6cc;" horiz-adv-x="304" arabic-form="medial"
+ d="M173 55l-59 -57l-61 57l61 57zM300 55l-59 -57l-61 57l61 57zM286 514c30 -41.3333 45 -88 45 -140v-69c0 -69.3333 -17.3333 -104.333 -52 -105h-252c-32.6667 0 -49 26 -49 78h320v10c0 64 -18.6667 113.667 -56 149z" />
+ <glyph glyph-name="uniFDF2" unicode="&#xfdf2;" horiz-adv-x="640" arabic-form="isolated"
+ d="M918 261c30 0 45 29 45 87c0 73.3333 -3.33331 125 -10 155l-29 132l55 29l19 -162c4 -43.3333 6.66669 -92.6667 8 -148v-20c0 -65.3333 -4.33331 -109 -13 -131s-28.3333 -33 -59 -33c-72.6667 1.33333 -112.333 26.3333 -119 75c-8 -50 -45 -75 -111 -75
+c-40 0 -74.3333 38 -103 114l-34 -30c-36 0.666672 -65 7.66666 -87 21s-33 30 -33 50c0 15.3333 3.16666 29.3333 9.5 42s16.5 24.1667 30.5 34.5s25.1667 18 33.5 23s21.6667 11.6667 40 20s27.8333 12.5 28.5 12.5v45l31 34c2 -51.3333 4.16669 -92.1667 6.5 -122.5
+s5.66669 -57.1667 10 -80.5s10.6667 -40.1667 19 -50.5s18.1667 -17.8333 29.5 -22.5c11.3333 -4.66667 26 -7 44 -7c27.3333 0 44.1667 4.5 50.5 13.5s9.5 27.8333 9.5 56.5c0 96 -8 186.333 -24 271l55 41c2 -156.667 11.3333 -270.667 28 -342c5.33331 -22 23 -33 53 -33
+c1.33331 0 3.33331 0.166656 6 0.5s5 0.5 7 0.5h4zM483 341c9.33334 -15.3333 19.8333 -25.6667 31.5 -31c11.6667 -5.33334 29.8333 -8 54.5 -8c10.6667 0 18.3333 0.333344 23 1v107c-60.6667 -22.6667 -97 -45.6667 -109 -69zM786 782c1.33331 0 5 -5 11 -15
+s13.3333 -15 22 -15c9.33331 6 14 14 14 24c0 5.33331 -1 10.3333 -3 15c2 4 4 6 6 6c2 0.666687 4.33331 -2.66669 7 -10s4 -19.6667 4 -37c0 -10.6667 -1.83331 -18 -5.5 -22s-10.5 -6 -20.5 -6c-7.33331 0 -17 1.66669 -29 5c-11.3333 -14 -21.6667 -21 -31 -21
+c-22.6667 0 -34 13.6667 -34 41c0 12 0.666687 22 2 30h2c2 0.666687 3.66669 -0.666687 5 -4s2.33331 -7 3 -11s2.16669 -7.83331 4.5 -11.5s5.5 -5.5 9.5 -5.5c4.66669 0 11 2.16669 19 6.5s12 10.5 12 18.5c0 3.33331 -0.333313 6 -1 8
+c0.666687 1.33331 1.66669 2.66669 3 4zM790 853c-2.66669 20 -12 42.3333 -28 67l28 30c3.33331 -18.6667 5 -37.6667 5 -57c0 -18 -1.66669 -31.3333 -5 -40z" />
+ <glyph glyph-name="uniFDFC" unicode="&#xfdfc;" horiz-adv-x="837" arabic-form="isolated"
+ d="M600 292c16 -20 26.6667 -38.3333 32 -55s8 -43.3333 8 -80v-84h-162c-24.6667 0 -41.8333 16.1667 -51.5 48.5c-9.66666 32.3333 -15.5 78.6667 -17.5 139c-2 60.3333 -4.66666 99.8333 -8 118.5c-5.33334 27.3333 -15.3333 48 -30 62l42 67
+c12.6667 -38 20.3333 -90.6667 23 -158l6 -154c5.33334 -42 17.3333 -63 36 -63h137c0 23.3333 -2.5 41.3333 -7.5 54s-16.5 29.3333 -34.5 50zM812 9c0 -33.3333 -19.8333 -68.8333 -59.5 -106.5c-39.6667 -37.6667 -75.8333 -56.5 -108.5 -56.5
+c-26.6667 0 -52 4.66667 -76 14l-73 28l5 13c45.3333 -8.66666 76 -13 92 -13c44 0 87.6667 19 131 57c42.6667 36.6667 64 71.6667 64 105c0 34 -17.3333 69.3333 -52 106l20 54c38 -34.6667 57 -73.6667 57 -117v-84zM638 5l-27 -49l-55 30l26 48zM560 -25l-27 -50l-55 29
+l25 49zM322 415c22.6667 -142 34 -239.667 34 -293c0 -52 -16 -88 -48 -108s-78.6667 -30 -140 -30c-94.6667 0 -142 34.6667 -142 104c0 46 19.6667 104.667 59 176l11 -6c-29.3333 -53.3333 -44 -96.6667 -44 -130c0 -56.6667 38.3333 -85 115 -85
+c36.6667 0 72.6667 6.66667 108 20c35.3333 13.3333 53 30.6667 53 52c0 43.3333 -14 148.333 -42 315l-15 8v8c0 26 6 51 18 75h6c0.666656 -14.6667 6 -24 16 -28l40 -18c0 -20 -3 -42 -9 -66z" />
+ <glyph glyph-name="uniFE70" unicode="&#xfe70;" arabic-form="isolated"
+ d="M190 1006l-78.5 -38c-19 -9.33331 -32.6667 -18.5 -41 -27.5c-8.33333 -9 -13.8333 -21.1667 -16.5 -36.5l151 74c15.3333 6.66669 26 14 32 22s10 19.6667 12 35zM190 916l-78.5 -38c-19 -9.33331 -32.6667 -18.5 -41 -27.5c-8.33333 -9 -13.8333 -21.1667 -16.5 -36.5
+l151 74c15.3333 6.66669 26 14 32 22s10 19.6667 12 35z" />
+ <glyph glyph-name="uniFE74" unicode="&#xfe74;" arabic-form="isolated"
+ d="M180 -153l-76 -37c-19.3333 -9.33333 -33.5 -18.8333 -42.5 -28.5s-14.8333 -22.1667 -17.5 -37.5l151 74c15.3333 6.66667 26 14 32 22s10 19.6667 12 35zM180 -63l-76 -37c-19.3333 -9.33334 -33.5 -18.8333 -42.5 -28.5c-9 -9.66667 -14.8333 -22.1667 -17.5 -37.5
+l151 74c15.3333 6.66666 26 14 32 22s10 19.6667 12 35z" />
+ <glyph glyph-name="uniFE76" unicode="&#xfe76;" arabic-form="isolated"
+ d="M190 1006l-78.5 -38c-19 -9.33331 -32.6667 -18.5 -41 -27.5c-8.33333 -9 -13.8333 -21.1667 -16.5 -36.5l151 74c15.3333 6.66669 26 14 32 22s10 19.6667 12 35z" />
+ <glyph glyph-name="uniFE78" unicode="&#xfe78;" arabic-form="isolated"
+ d="M219 1010c16 -7.33331 26 -13 30 -17s6 -9.33331 6 -16c0 -7.33331 -2 -15.6667 -6 -25l-50 23c-22.6667 -42.6667 -65 -76 -127 -100h-21c47.3333 26 88.6667 63.3333 124 112l-34 28c-9.33333 8.66669 -14 20.3334 -14 35c0 23.3334 8.66667 43.1666 26 59.5
+s34.3333 24.5 51 24.5c20.6667 0 31 -14 31 -42c0 -19.3334 -5.33333 -46.6666 -16 -82zM201 1052c0 12 -1.66667 20.3334 -5 25s-10.3333 7 -21 7c-9.33333 0 -14 -5.33337 -14 -16c0 -8.66663 13 -22.6666 39 -42c0.666672 6.66663 1 15.3334 1 26z" />
+ <glyph glyph-name="uniFE7A" unicode="&#xfe7a;" arabic-form="isolated"
+ d="M180 -153l-76 -37c-19.3333 -9.33333 -33.5 -18.8333 -42.5 -28.5s-14.8333 -22.1667 -17.5 -37.5l151 74c15.3333 6.66667 26 14 32 22s10 19.6667 12 35z" />
+ <glyph glyph-name="uniFE7C" unicode="&#xfe7c;" arabic-form="isolated"
+ d="M250 1011c-0.666672 -8 -5.83333 -18.1667 -15.5 -30.5s-21.1667 -18.5 -34.5 -18.5c-3.33333 0 -9 1.33331 -17 4c-12 -30 -29 -45 -51 -45c-12.6667 0 -23.1667 5.16669 -31.5 15.5s-12.5 23.5 -12.5 39.5c0 9.33331 1.66666 21.6667 5 37h7
+c-3.33334 -12 -5 -21.3333 -5 -28c0 -10 2.66666 -18 8 -24s12.3333 -9 21 -9c4.66667 0 8.5 0.666687 11.5 2s7.83333 6 14.5 14s14.6667 20.3333 24 37c7.33333 -9.33331 14.6667 -14 22 -14s15 4.33331 23 13s12 17 12 25c0 14 -7.66667 25.6666 -23 35l6 12
+c24 -33.3334 36 -55 36 -65z" />
+ <glyph glyph-name="uniFE81" unicode="&#x622;" horiz-adv-x="321" arabic-form="isolated"
+ d="M155 1055c10 0 23.5 -0.5 40.5 -1.5s29.8333 -1.5 38.5 -1.5c24 0 42.8333 2.83337 56.5 8.5s35.8333 20.5 66.5 44.5l-17 -55c-12 -19.3334 -27 -32.6667 -45 -40s-46 -11 -84 -11c-3.33333 0 -13.6667 0.333313 -31 1s-33 1 -47 1
+c-10.6667 -0.666687 -19.8333 -0.5 -27.5 0.5s-19.3333 -2.83331 -35 -11.5c-15.6667 -8.66669 -35.1667 -23.3333 -58.5 -44c22.6667 45.3333 42 74.8333 58 88.5c16 13.6666 44.3333 20.5 85 20.5zM149 154c18 210.667 27 343 27 397c0 56.6667 -3 143 -9 259l42 89
+c9.33333 -170 14 -309.333 14 -418c0 -114 -24.6667 -223 -74 -327z" />
+ <glyph glyph-name="uniFE8C" unicode="&#x626;" horiz-adv-x="301" arabic-form="medial"
+ d="M175 653c0 14.6667 7.66667 34.6667 23 60s35 38 59 38h5c27.3333 -1.33331 41.6667 -16 43 -44c-12 8 -23 12 -33 12c-12 0 -24 -5.33331 -36 -16s-18 -20 -18 -28c0 -6 4.83333 -14.8333 14.5 -26.5s20.8333 -17.5 33.5 -17.5c13.3333 0 32.3333 3.33331 57 10
+c-39.3333 -34 -91.6667 -62.3333 -157 -85c11.3333 22 28.6667 38.3333 52 49c-28.6667 14 -43 30 -43 48zM271 509c28.6667 -42.6667 43 -89.6667 43 -141v-70c0 -70.6667 -16.6667 -106 -50 -106h-240c-30.6667 0 -46 26.3333 -46 79h304v11
+c0 64.6667 -17.3333 114.667 -52 150z" />
+ <glyph glyph-name="uniFE8D" unicode="&#x627;" horiz-adv-x="249" arabic-form="isolated"
+ d="M149 154l13.5 182c4.33333 56 7.33333 93.1667 9 111.5s2.83333 35.6667 3.5 52c0.666672 16.3333 1 33.8333 1 52.5c0 56.6667 -3 143 -9 259l42 89c9.33333 -170 14 -309.667 14 -419c0 -114 -24.6667 -223 -74 -327z" />
+ <glyph glyph-name="uniFE8E" unicode="&#x627;" horiz-adv-x="275" arabic-form="terminal"
+ d="M215 699c0 -50 -3 -100.5 -9 -151.5s-9 -91.1667 -9 -120.5c0 -30.6667 4 -64 12 -100c7.33333 -30.6667 36.6667 -46 88 -46h5v-81c-58 0 -98.6667 16.3333 -122 49c-23.3333 32.6667 -36.6667 82 -40 148c10.6667 84.6667 16 171.333 16 260
+c0 57.3333 -1.66667 106.333 -5 147l47 97c11.3333 -68 17 -135.333 17 -202z" />
+ <glyph glyph-name="uniFE8F" unicode="&#x628;" horiz-adv-x="950" arabic-form="isolated"
+ d="M644 2l-52 -54l-52 54l52 53zM926 278c0 43.3333 -3 78 -9 104s-11.5 42.3333 -16.5 49s-13.8333 15.3333 -26.5 26l18 64c43.3333 -27.3333 65 -68.6667 65 -124c0 -3.33334 -0.333313 -7.66666 -1 -13s-1 -9.66666 -1 -13v-174h-718c-37.3333 0 -65.1667 7 -83.5 21
+s-27.5 39.3333 -27.5 76c0 52 23.3333 119.667 70 203l10 -9c-34.6667 -69.3333 -52 -116.333 -52 -141c0 -24 14 -47 42 -69h730z" />
+ <glyph glyph-name="uniFE90" unicode="&#x628;" horiz-adv-x="950" arabic-form="terminal"
+ d="M644 2l-52 -54l-52 54l52 53zM926 278c0 43.3333 -3 78 -9 104s-11.5 42.3333 -16.5 49s-13.8333 15.3333 -26.5 26l18 64c43.3333 -27.3333 65 -68.6667 65 -124c0 -3.33334 -0.333313 -7.66666 -1 -13s-1 -9.66666 -1 -13v-174h-718c-37.3333 0 -65.1667 7 -83.5 21
+s-27.5 39.3333 -27.5 76c0 52 23.3333 119.667 70 203l10 -9c-34.6667 -69.3333 -52 -116.333 -52 -141c0 -24 14 -47 42 -69h730z" />
+ <glyph glyph-name="uniFE91" unicode="&#x628;" horiz-adv-x="293" arabic-form="initial"
+ d="M251 29l-67 -69l-68 69l68 68zM274 525c30 -43.3333 45 -92.6667 45 -148v-73c0 -74 -17.3333 -111 -52 -111h-271l2 83h288v11c0 68 -18.3333 120.333 -55 157z" />
+ <glyph glyph-name="uniFE92" unicode="&#x628;" horiz-adv-x="293" arabic-form="medial"
+ d="M251 29l-67 -69l-68 69l68 68zM274 525c30 -43.3333 45 -92.6667 45 -148v-73c0 -74 -17.3333 -111 -52 -111h-271l2 83h288v11c0 68 -18.3333 120.333 -55 157z" />
+ <glyph glyph-name="uniFE95" unicode="&#x62a;" horiz-adv-x="925" arabic-form="isolated"
+ d="M530 574l-65 -66l-67 66l67 67zM740 574l-65 -66l-67 66l67 67zM895 277c0 52.6667 -3 90.3333 -9 113s-19.6667 43 -41 61l17 61c42 -26 63 -65.6667 63 -119c0 -3.33334 -0.333313 -7.66666 -1 -13s-1 -9.33334 -1 -12v-169h-693
+c-34.6667 0 -61.1667 6.83333 -79.5 20.5s-27.5 38.1667 -27.5 73.5c0 50 22.6667 115.333 68 196l9 -8c-33.3333 -66.6667 -50 -112.333 -50 -137c0 -23.3333 13.6667 -45.6667 41 -67h704z" />
+ <glyph glyph-name="uniFE96" unicode="&#x62a;" horiz-adv-x="925" arabic-form="terminal"
+ d="M530 574l-65 -66l-67 66l67 67zM740 574l-65 -66l-67 66l67 67zM895 277c0 52.6667 -3 90.3333 -9 113s-19.6667 43 -41 61l17 61c42 -26 63 -65.6667 63 -119c0 -3.33334 -0.333313 -7.66666 -1 -13s-1 -9.33334 -1 -12v-169h-693
+c-34.6667 0 -61.1667 6.83333 -79.5 20.5s-27.5 38.1667 -27.5 73.5c0 50 22.6667 115.333 68 196l9 -8c-33.3333 -66.6667 -50 -112.333 -50 -137c0 -23.3333 13.6667 -45.6667 41 -67h704z" />
+ <glyph glyph-name="uniFE97" unicode="&#x62a;" horiz-adv-x="308" arabic-form="initial"
+ d="M150 689l-57 -58l-59 58l59 59zM295 688l-57 -59l-59 59l59 58zM254 533c29.3333 -44 44 -93.3333 44 -148v-74c0 -74 -17 -111 -51 -111h-251l-8 83h277v15c0 65.3333 -18.3333 116.333 -55 153z" />
+ <glyph glyph-name="uniFE98" unicode="&#x62a;" horiz-adv-x="308" arabic-form="medial"
+ d="M150 689l-57 -58l-59 58l59 59zM295 688l-57 -59l-59 59l59 58zM254 533c29.3333 -44 44 -93.3333 44 -148v-74c0 -74 -17 -111 -51 -111h-251l-8 83h277v15c0 65.3333 -18.3333 116.333 -55 153z" />
+ <glyph glyph-name="uniFE99" unicode="&#x62b;" horiz-adv-x="924" arabic-form="isolated"
+ d="M756 543l-64 -66l-67 66l67 67zM531 543l-64 -66l-67 66l67 67zM643 665l-65 -67l-66 67l66 66zM921 275c0 54 -3 92.6667 -9 116s-20 44 -42 62l17 63c43.3333 -27.3333 65 -68.3333 65 -123c0 -3.33334 -0.333313 -7.66666 -1 -13s-1 -9.66666 -1 -13v-173h-713
+c-36.6667 0 -64.1667 7 -82.5 21s-27.5 39.3333 -27.5 76c0 52 23.3333 119 70 201l9 -8c-34 -68 -51 -114.667 -51 -140c0 -24 14 -47 42 -69h724z" />
+ <glyph glyph-name="uniFE9A" unicode="&#x62b;" horiz-adv-x="924" arabic-form="terminal"
+ d="M756 543l-64 -66l-67 66l67 67zM531 543l-64 -66l-67 66l67 67zM643 665l-65 -67l-66 67l66 66zM921 275c0 54 -3 92.6667 -9 116s-20 44 -42 62l17 63c43.3333 -27.3333 65 -68.3333 65 -123c0 -3.33334 -0.333313 -7.66666 -1 -13s-1 -9.66666 -1 -13v-173h-713
+c-36.6667 0 -64.1667 7 -82.5 21s-27.5 39.3333 -27.5 76c0 52 23.3333 119 70 201l9 -8c-34 -68 -51 -114.667 -51 -140c0 -24 14 -47 42 -69h724z" />
+ <glyph glyph-name="uniFE9B" unicode="&#x62b;" horiz-adv-x="298" arabic-form="initial"
+ d="M163 675l-61 -61l-61 61l61 62zM293 673l-60 -61l-62 61l62 62zM230 794l-61 -62l-61 62l61 61zM264 532c30 -43.3333 45 -92.6667 45 -148v-73c0 -74 -17.3333 -111 -52 -111h-251l-8 83h278v11c0 68 -18.3333 120.333 -55 157z" />
+ <glyph glyph-name="uniFE9C" unicode="&#x62b;" horiz-adv-x="298" arabic-form="medial"
+ d="M163 675l-61 -61l-61 61l61 62zM293 673l-60 -61l-62 61l62 62zM230 794l-61 -62l-61 62l61 61zM264 532c30 -43.3333 45 -92.6667 45 -148v-73c0 -74 -17.3333 -111 -52 -111h-251l-8 83h278v11c0 68 -18.3333 120.333 -55 157z" />
+ <glyph glyph-name="uniFE9D" unicode="&#x62c;" horiz-adv-x="750" arabic-form="isolated"
+ d="M330 491c10.6667 0 47.6667 -5.5 111 -16.5s132 -16.5 206 -16.5l88 2l-20 -63h-5c-116 0 -213.833 -17 -293.5 -51s-144.167 -86.6667 -193.5 -158c-36 -50.6667 -54 -103.333 -54 -158c0 -23.3333 2.83333 -45.8333 8.5 -67.5c5.66667 -21.6667 15 -43 28 -64
+s32.1667 -37.8333 57.5 -50.5c25.3333 -12.6667 55.6667 -19 91 -19c72.6667 0 171.667 15.6667 297 47l48 -47c-104.667 -32.6667 -211 -51 -319 -55h-26c-88 9.33333 -147.333 35.3333 -178 78c-30 40.6667 -45 68 -45 82c-4.66666 14 -7 31.6667 -7 53
+c0 45.3333 10.5 87.6667 31.5 127c21 39.3333 52.1667 84 93.5 134c95.3333 78.6667 174.333 126.667 237 144c-37.3333 10 -73.5 19 -108.5 27s-70.1667 12 -105.5 12c-34.6667 0 -56 -5.66666 -64 -17l-27 -10c30.6667 32 56 54.5 76 67.5s44.3333 19.5 73 19.5zM497 104
+l-53 -53l-52 53l52 51z" />
+ <glyph glyph-name="uniFE9E" unicode="&#x62c;" horiz-adv-x="750" arabic-form="terminal"
+ d="M497 84l-53 -53l-52 53l52 52zM778 192h-45c-43.3333 4 -71.1667 20.8333 -83.5 50.5c-12.3333 29.6667 -18.8333 78.5 -19.5 146.5l8 -10c4 -23.3333 7.16669 -39.8333 9.5 -49.5s6.5 -20 12.5 -31s14 -18.1667 24 -21.5s23.6667 -5 41 -5h56zM337 494
+c9.33334 0 46.3333 -5.5 111 -16.5c64.6667 -11 136.333 -16.5 215 -16.5l91 1l-21 -63h-5c-119.333 0 -220 -17 -302 -51s-148.333 -87 -199 -159c-36.6667 -52 -55 -104.667 -55 -158c0 -18 1.66667 -35.6667 5 -53c3.33333 -17.3333 9.33333 -35.3333 18 -54
+c8.66667 -18.6667 19.8333 -35 33.5 -49s32 -25.5 55 -34.5s49.1667 -13.5 78.5 -13.5c74.6667 0 180.333 15.6667 317 47l37 -48c-108 -32.6667 -217 -51 -327 -55h-28c-90 9.33333 -151 35.3333 -183 78c-30.6667 41.3333 -46 69.3333 -46 84
+c-4.66666 13.3333 -7 31 -7 53c0 45.3333 10.6667 88.1667 32 128.5c21.3333 40.3333 53.3333 85.1667 96 134.5c98.6667 80.6667 180 129.333 244 146c-16 3.33334 -39.5 9 -70.5 17s-57 13.5 -78 16.5s-44.8333 4.5 -71.5 4.5c-35.3333 0 -57 -5.66666 -65 -17l-28 -10
+c22 22 38.6667 37.8333 50 47.5s26.1667 18.8333 44.5 27.5s37.8333 13 58.5 13z" />
+ <glyph glyph-name="uniFE9F" unicode="&#x62c;" horiz-adv-x="574" arabic-form="initial"
+ d="M128 383c68.6667 50.6667 117.667 76 147 76c12.6667 0 33.5 -8.83334 62.5 -26.5s54.8333 -36.5 77.5 -56.5c60.6667 -64 123.333 -97.3333 188 -100l2 -76h-585c-15.3333 0 -23 24.6667 -23 74l458 2l-126 88c-13.3333 8.66666 -31 18.1667 -53 28.5
+s-39.6667 15.5 -53 15.5c-10 0 -41.6667 -8.33334 -95 -25zM357 44l-53 -53l-52 53l52 52z" />
+ <glyph glyph-name="uniFEA0" unicode="&#x62c;" horiz-adv-x="574" arabic-form="medial"
+ d="M128 383c68.6667 50.6667 117.667 76 147 76c12.6667 0 33.5 -8.83334 62.5 -26.5s54.8333 -36.5 77.5 -56.5c60.6667 -64 123.333 -97.3333 188 -100l2 -76h-585c-15.3333 0 -23 24.6667 -23 74l458 2l-126 88c-13.3333 8.66666 -31 18.1667 -53 28.5
+s-39.6667 15.5 -53 15.5c-10 0 -41.6667 -8.33334 -95 -25zM357 44l-53 -53l-52 53l52 52z" />
+ <glyph glyph-name="uniFEA1" unicode="&#x62d;" horiz-adv-x="748" arabic-form="isolated"
+ d="M330 505c8 0 44.5 -5.33334 109.5 -16s134.833 -16 209.5 -16l89 1l-20 -62h-5c-117.333 0 -216 -16.6667 -296 -50s-145 -85.3333 -195 -156c-36 -50 -54 -101.667 -54 -155c0 -22.6667 2.83333 -44.6667 8.5 -66c5.66667 -21.3333 15 -42.5 28 -63.5
+s32.3333 -38 58 -51c25.6667 -13 56.1667 -19.5 91.5 -19.5c76 0 179.333 15 310 45l37 -46c-106 -32 -212.667 -50 -320 -54h-27c-88.6667 9.33333 -148.667 35 -180 77c-30 39.3333 -45 66.6667 -45 82c-4.66666 13.3333 -7 30.6667 -7 52
+c0 44.6667 10.6667 86.8333 32 126.5c21.3333 39.6667 52.6667 83.5 94 131.5c96.6667 78.6667 176.333 126.333 239 143c-32.6667 8.66666 -68.1667 17 -106.5 25s-75.1667 12 -110.5 12c-33.3333 0 -54.3333 -5.33334 -63 -16l-27 -10
+c34.6667 34.6667 61.8333 57.6667 81.5 69c19.6667 11.3333 42.5 17 68.5 17z" />
+ <glyph glyph-name="uniFEA2" unicode="&#x62d;" horiz-adv-x="750" arabic-form="terminal"
+ d="M638 389c4 -23.3333 7.16669 -39.8333 9.5 -49.5s6.5 -20 12.5 -31s14 -18.1667 24 -21.5s23.6667 -5 41 -5h56l-3 -80h-45c-18 2 -33.6667 7.16667 -47 15.5s-23.5 18 -30.5 29s-12.5 25.1667 -16.5 42.5s-6.5 33.1667 -7.5 47.5s-1.5 31.8333 -1.5 52.5h8zM337 494
+c9.33334 0 46.3333 -5.5 111 -16.5c64.6667 -11 136.333 -16.5 215 -16.5l91 1l-21 -63h-5c-119.333 0 -220 -17 -302 -51s-148.333 -87 -199 -159c-36.6667 -52 -55 -104.667 -55 -158c0 -22.6667 2.83333 -45 8.5 -67s15.1667 -43.8333 28.5 -65.5s33 -39 59 -52
+s57 -19.5 93 -19.5c74 0 176.667 15.6667 308 47l37 -58c-102 -26 -207.667 -41 -317 -45h-28c-90 9.33333 -151 35.3333 -183 78c-30.6667 41.3333 -46 69.3333 -46 84c-4.66666 13.3333 -7 31 -7 53c0 45.3333 10.6667 88.1667 32 128.5
+c21.3333 40.3333 53.3333 85.1667 96 134.5c98.6667 80.6667 180 129.333 244 146c-16 3.33334 -39.5 9 -70.5 17s-57 13.5 -78 16.5s-44.8333 4.5 -71.5 4.5c-35.3333 0 -57 -5.66666 -65 -17l-28 -10c22 22 38.6667 37.8333 50 47.5s26.1667 18.8333 44.5 27.5
+s37.8333 13 58.5 13z" />
+ <glyph glyph-name="uniFEA3" unicode="&#x62d;" horiz-adv-x="600" arabic-form="initial"
+ d="M148 353c18.6667 25.3333 32.6667 43.6667 42 55s22 22.6667 38 34s32 17 48 17c19.3333 0 47.6667 -12.8333 85 -38.5s75.6667 -57.1667 115 -94.5c20 -23.3333 62.6667 -40 128 -50l2 -76h-586c-15.3333 0 -23 24.6667 -23 74l459 2l-126 88
+c-15.3333 10.6667 -32 16 -50 16c-23.3333 0 -62 -10 -116 -30z" />
+ <glyph glyph-name="uniFEA4" unicode="&#x62d;" horiz-adv-x="600" arabic-form="medial"
+ d="M148 353c18.6667 25.3333 32.6667 43.6667 42 55s22 22.6667 38 34s32 17 48 17c19.3333 0 47.6667 -12.8333 85 -38.5s75.6667 -57.1667 115 -94.5c20 -23.3333 62.6667 -40 128 -50l2 -76h-586c-15.3333 0 -23 24.6667 -23 74l459 2l-126 88
+c-15.3333 10.6667 -32 16 -50 16c-23.3333 0 -62 -10 -116 -30z" />
+ <glyph glyph-name="uniFEA5" unicode="&#x62e;" horiz-adv-x="701" arabic-form="isolated"
+ d="M308 503c11.3333 0 46.6667 -5.16666 106 -15.5s124.333 -15.5 195 -15.5l84 2l-19 -59h-5c-216.667 0 -371 -65 -463 -195c-34 -46.6667 -51 -95 -51 -145c0 -21.3333 2.66667 -42 8 -62s13.8333 -40 25.5 -60s29.3333 -36.1667 53 -48.5
+c23.6667 -12.3333 51.8333 -18.5 84.5 -18.5c70 0 171 19.6667 303 59l29 -60c-100 -30 -200.667 -47 -302 -51h-25c-84.6667 8.66667 -141.333 32.6667 -170 72c-28 38 -42 64 -42 78c-4.66666 12 -7 28.3333 -7 49c0 44 10.1667 84.6667 30.5 122
+c20.3333 37.3333 49.8333 78 88.5 122c91.3333 73.3333 166.333 118 225 134c-32 8.66666 -66.1667 16.6667 -102.5 24s-70.8333 11 -103.5 11c-30.6667 0 -50 -5 -58 -15l-25 -9c30 30 54.3333 51 73 63c18.6667 12 41.3333 18 68 18zM379 680l-44 -44l-43 44l43 43z" />
+ <glyph glyph-name="uniFEA6" unicode="&#x62e;" horiz-adv-x="775" arabic-form="terminal"
+ d="M474 696l-54 -54l-53 54l53 53zM790 201h-45c-40.6667 4 -68.3333 18.6667 -83 44c-14.6667 25.3333 -22.3333 74.3333 -23 147l9 -11c6.66669 -44 14.8333 -73 24.5 -87s30.8333 -21 63.5 -21h57zM341 499c10.6667 0 49.3333 -5.66666 116 -17
+c66.6667 -11.3333 138.667 -17 216 -17l92 2l-20 -65h-5c-121.333 0 -223.833 -17.5 -307.5 -52.5c-83.6667 -35 -151.833 -88.8333 -204.5 -161.5c-36.6667 -52.6667 -55 -106.667 -55 -162c0 -17.3333 1.33333 -34.3333 4 -51c2.66667 -16.6667 8.33333 -34.8333 17 -54.5
+c8.66667 -19.6667 20 -36.6667 34 -51c14 -14.3333 33.1667 -26.3333 57.5 -36s52.5 -14.5 84.5 -14.5c78.6667 0 185.667 16.3333 321 49l36 -51c-112 -33.3333 -223 -52 -333 -56h-28c-91.3333 9.33333 -153.667 36 -187 80c-31.3333 42 -47 70.3333 -47 85
+c-4.66666 14 -7 32.3333 -7 55c0 46.6667 11 90.6667 33 132c22 41.3333 54.6667 86.6667 98 136c99.3333 81.3333 182 131 248 149c-16 3.33334 -39.1667 8.83334 -69.5 16.5s-56.8333 13.3333 -79.5 17s-48 5.5 -76 5.5c-35.3333 0 -57.3333 -5.66666 -66 -17l-28 -11
+c23.3333 23.3333 40.8333 40 52.5 50s26.6667 19.1667 45 27.5s37.8333 12.5 58.5 12.5z" />
+ <glyph glyph-name="uniFEA7" unicode="&#x62e;" horiz-adv-x="596" arabic-form="initial"
+ d="M320 618l-50 -49l-48 49l48 48zM147 351c9.33333 13.3333 19.1667 26.3333 29.5 39s20 23.8333 29 33.5s19.3333 17.5 31 23.5s23.8333 9 36.5 9c38 0 104 -44 198 -132c19.3333 -22.6667 62 -39 128 -49l1 -75h-580c-15.3333 0 -23 24.3333 -23 73l455 2l-91 64.5
+c-22 15 -38.6667 25.1667 -50 30.5s-22.6667 8 -34 8c-23.3333 0 -61.6667 -10 -115 -30z" />
+ <glyph glyph-name="uniFEA8" unicode="&#x62e;" horiz-adv-x="596" arabic-form="medial"
+ d="M320 618l-50 -49l-48 49l48 48zM147 351c9.33333 13.3333 19.1667 26.3333 29.5 39s20 23.8333 29 33.5s19.3333 17.5 31 23.5s23.8333 9 36.5 9c38 0 104 -44 198 -132c19.3333 -22.6667 62 -39 128 -49l1 -75h-580c-15.3333 0 -23 24.3333 -23 73l455 2l-91 64.5
+c-22 15 -38.6667 25.1667 -50 30.5s-22.6667 8 -34 8c-23.3333 0 -61.6667 -10 -115 -30z" />
+ <glyph glyph-name="uniFEA9" unicode="&#x62f;" horiz-adv-x="397" arabic-form="isolated"
+ d="M382 278c-4 16.6667 -6.5 31 -7.5 43s-3.16666 23.3333 -6.5 34s-5.83334 19.6667 -7.5 27s-5 14.8333 -10 22.5s-9.66666 14.1667 -14 19.5s-10.8333 11.3333 -19.5 18s-17.6667 13.1667 -27 19.5l-36 23.5l2 79c14.6667 -4.66669 26.6667 -9 36 -13
+s22.6667 -12.6667 40 -26c17.3333 -13.3333 31.6667 -29.3333 43 -48s22.1667 -45.3333 32.5 -80s16.8333 -74.3333 19.5 -119c0 -52 -18.6667 -78 -56 -78h-202c-36.6667 0 -55 32 -55 96v21l12 1c2.66667 -25.3333 12 -38.6667 28 -40h228z" />
+ <glyph glyph-name="uniFEAA" unicode="&#x62f;" horiz-adv-x="397" arabic-form="terminal"
+ d="M382 278c-4 16.6667 -6.5 31 -7.5 43s-3.16666 23.3333 -6.5 34s-5.83334 19.6667 -7.5 27s-5 14.8333 -10 22.5s-9.66666 14.1667 -14 19.5s-10.8333 11.3333 -19.5 18s-17.6667 13.1667 -27 19.5l-36 23.5l2 79c14.6667 -4.66669 26.6667 -9 36 -13
+s22.6667 -12.6667 40 -26c17.3333 -13.3333 31.6667 -29.3333 43 -48s22.1667 -45.3333 32.5 -80s16.8333 -74.3333 19.5 -119c0 -52 -18.6667 -78 -56 -78h-202c-36.6667 0 -55 32 -55 96v21l12 1c2.66667 -25.3333 12 -38.6667 28 -40h228z" />
+ <glyph glyph-name="uniFEAB" unicode="&#x630;" horiz-adv-x="399" arabic-form="isolated"
+ d="M303 725l-57 -57l-55 57l55 55zM378 277c-6 23.3333 -9.33334 42.3333 -10 57s-3.5 28.3333 -8.5 41l-12 30c-3 7.33334 -9.33334 15.3333 -19 24s-19.6667 16.6667 -30 24s-25.8333 17 -46.5 29l2 78c14 -4.66669 25.6667 -9 35 -13s22.6667 -12.6667 40 -26
+c17.3333 -13.3333 31.5 -29.1667 42.5 -47.5s21.6667 -44.6667 32 -79s16.8333 -73.5 19.5 -117.5c0 -51.3333 -18.3333 -77 -55 -77h-200c-36 0 -54 31.6667 -54 95v20l12 2c2.66667 -25.3333 12 -38.6667 28 -40h224z" />
+ <glyph glyph-name="uniFEAC" unicode="&#x630;" horiz-adv-x="399" arabic-form="terminal"
+ d="M303 725l-57 -57l-55 57l55 55zM378 277c-6 23.3333 -9.33334 42.3333 -10 57s-3.5 28.3333 -8.5 41l-12 30c-3 7.33334 -9.33334 15.3333 -19 24s-19.6667 16.6667 -30 24s-25.8333 17 -46.5 29l2 78c14 -4.66669 25.6667 -9 35 -13s22.6667 -12.6667 40 -26
+c17.3333 -13.3333 31.5 -29.1667 42.5 -47.5s21.6667 -44.6667 32 -79s16.8333 -73.5 19.5 -117.5c0 -51.3333 -18.3333 -77 -55 -77h-200c-36 0 -54 31.6667 -54 95v20l12 2c2.66667 -25.3333 12 -38.6667 28 -40h224z" />
+ <glyph glyph-name="uniFEAD" unicode="&#x631;" horiz-adv-x="328" arabic-form="isolated"
+ d="M325 447c13.3333 -46 20 -95.3333 20 -148c0 -14.6667 -1.66666 -34 -5 -58s-5.33334 -39.3333 -6 -46l-128 -241c-32 -48 -66.3333 -76 -103 -84l-104 -23l5 21c55.3333 32.6667 90.6667 59.6667 106 81l69 100c46 66.6667 75.1667 113.5 87.5 140.5
+c12.3333 27 18.5 53.1667 18.5 78.5c0 30 -6 74 -18 132z" />
+ <glyph glyph-name="uniFEAE" unicode="&#x631;" horiz-adv-x="328" arabic-form="terminal"
+ d="M325 447c13.3333 -46 20 -95.3333 20 -148c0 -14.6667 -1.66666 -34 -5 -58s-5.33334 -39.3333 -6 -46l-128 -241c-32 -48 -66.3333 -76 -103 -84l-104 -23l5 21c55.3333 32.6667 90.6667 59.6667 106 81l69 100c46 66.6667 75.1667 113.5 87.5 140.5
+c12.3333 27 18.5 53.1667 18.5 78.5c0 30 -6 74 -18 132z" />
+ <glyph glyph-name="uniFEAF" unicode="&#x632;" horiz-adv-x="331" arabic-form="isolated"
+ d="M326 601l-56 -56l-59 56l59 53zM325 447c13.3333 -46 20 -95.3333 20 -148c0 -14.6667 -1.66666 -34 -5 -58s-5.33334 -39.3333 -6 -46l-128 -241c-28.6667 -35.3333 -63 -63.3333 -103 -84l-104 -23l5 21c54 38.6667 89.3333 67.3333 106 86
+c48.6667 58 90 116.5 124 175.5s51 105.167 51 138.5c0 30 -6 74 -18 132z" />
+ <glyph glyph-name="uniFEB0" unicode="&#x632;" horiz-adv-x="331" arabic-form="terminal"
+ d="M326 648l-63 -63l-67 63l67 60zM325 447c13.3333 -46 20 -95.3333 20 -148c0 -14.6667 -1.66666 -34 -5 -58s-5.33334 -39.3333 -6 -46l-128 -241c-28.6667 -35.3333 -63 -63.3333 -103 -84l-104 -23l5 21c54 38.6667 89.3333 67.3333 106 86
+c48.6667 58 90 116.5 124 175.5s51 105.167 51 138.5c0 30 -6 74 -18 132z" />
+ <glyph glyph-name="uniFEB1" unicode="&#x633;" horiz-adv-x="951" arabic-form="isolated"
+ d="M882 274c35.3333 0 53 6.33334 53 19c0 17.3333 -13.3333 56 -40 116l23 36c30 -67.3333 45 -118.333 45 -153c0 -36.6667 -6.83331 -60.5 -20.5 -71.5s-34.1667 -16.5 -61.5 -16.5h-19c-21.3333 1.33333 -43 12 -65 32c-16.6667 -22.6667 -37 -34 -61 -34
+c-38.6667 0 -74.3333 -0.333328 -107 -1c0 -30 -2.66669 -56.5 -8 -79.5s-11.5 -41 -18.5 -54s-17.6667 -24.8333 -32 -35.5c-14.3333 -10.6667 -26.1667 -18.1667 -35.5 -22.5c-9.33331 -4.33333 -23.6667 -10.1667 -43 -17.5c-42 -16.6667 -92.6667 -25 -152 -25h-33
+c-22.6667 1.33333 -42.8333 4 -60.5 8c-17.6667 4 -36.8333 11 -57.5 21s-36.6667 25.8333 -48 47.5c-11.3333 21.6667 -17 48.1667 -17 79.5c0 42.6667 27.3333 117.333 82 224l13 -23c-44.6667 -69.3333 -67 -122 -67 -158c0 -48 9.66667 -80.8333 29 -98.5
+c19.3333 -17.6667 52.3333 -30.1667 99 -37.5c17.3333 -3.33333 38.6667 -5 64 -5c42 0 86.1667 6.83333 132.5 20.5c46.3333 13.6667 74.5 27.1667 84.5 40.5c20 32 30 71.6667 30 119s-14 87 -42 119l33 72c21.3333 -37.3333 34.3333 -77.3333 39 -120h107
+c26.6667 0 40 23 40 69v15l13 7c8.66669 -36.6667 19 -61.3333 31 -74s35.3333 -19 70 -19z" />
+ <glyph glyph-name="uniFEB2" unicode="&#x633;" horiz-adv-x="951" arabic-form="terminal"
+ d="M882 274c35.3333 0 53 6.33334 53 19c0 17.3333 -13.3333 56 -40 116l23 36c30 -67.3333 45 -118.333 45 -153c0 -36.6667 -6.83331 -60.5 -20.5 -71.5s-34.1667 -16.5 -61.5 -16.5h-19c-21.3333 1.33333 -43 12 -65 32c-16.6667 -22.6667 -37 -34 -61 -34
+c-38.6667 0 -74.3333 -0.333328 -107 -1c0 -30 -2.66669 -56.5 -8 -79.5s-11.5 -41 -18.5 -54s-17.6667 -24.8333 -32 -35.5c-14.3333 -10.6667 -26.1667 -18.1667 -35.5 -22.5c-9.33331 -4.33333 -23.6667 -10.1667 -43 -17.5c-42 -16.6667 -92.6667 -25 -152 -25h-33
+c-22.6667 1.33333 -42.8333 4 -60.5 8c-17.6667 4 -36.8333 11 -57.5 21s-36.6667 25.8333 -48 47.5c-11.3333 21.6667 -17 48.1667 -17 79.5c0 42.6667 27.3333 117.333 82 224l13 -23c-44.6667 -69.3333 -67 -122 -67 -158c0 -48 9.66667 -80.8333 29 -98.5
+c19.3333 -17.6667 52.3333 -30.1667 99 -37.5c17.3333 -3.33333 38.6667 -5 64 -5c42 0 86.1667 6.83333 132.5 20.5c46.3333 13.6667 74.5 27.1667 84.5 40.5c20 32 30 71.6667 30 119s-14 87 -42 119l33 72c21.3333 -37.3333 34.3333 -77.3333 39 -120h107
+c26.6667 0 40 23 40 69v15l13 7c8.66669 -36.6667 19 -61.3333 31 -74s35.3333 -19 70 -19z" />
+ <glyph glyph-name="uniFEB3" unicode="&#x633;" horiz-adv-x="600" arabic-form="initial"
+ d="M523 272c22.6667 0 37.8333 2 45.5 6s11.5 12.3333 11.5 25c0 17.3333 -17.3333 53 -52 107l23 54c38 -54 57 -95.6667 57 -125v-83c0 -24 -4 -39.3333 -12 -46s-26.3333 -10 -55 -10c-30 0 -55 12.6667 -75 38c-22 -25.3333 -41.3333 -38 -58 -38h-83
+c-19.3333 0 -38 12.6667 -56 38c-18 -25.3333 -37 -38 -57 -38h-197c-10 0 -17 25 -21 75c148 0 228.667 1 242 3c14.6667 2.66666 22 14 22 34c0 14 -5.33333 38.6667 -16 74l14 19c7.33334 -29.3333 12.5 -52.8333 15.5 -70.5s8 -31.1667 15 -40.5
+s15.6667 -15.3333 26 -18s26.5 -4 48.5 -4c50.6667 0 76 14.3333 76 43c0 16.6667 -6 40.6667 -18 72l9 18c14 -42.6667 25.5 -73.1667 34.5 -91.5s17.5 -29.8333 25.5 -34.5s19.6667 -7 35 -7z" />
+ <glyph glyph-name="uniFEB4" unicode="&#x633;" horiz-adv-x="600" arabic-form="medial"
+ d="M523 272c22.6667 0 37.8333 2 45.5 6s11.5 12.3333 11.5 25c0 17.3333 -17.3333 53 -52 107l23 54c38 -54 57 -95.6667 57 -125v-83c0 -24 -4 -39.3333 -12 -46s-26.3333 -10 -55 -10c-30 0 -55 12.6667 -75 38c-22 -25.3333 -41.3333 -38 -58 -38h-83
+c-19.3333 0 -38 12.6667 -56 38c-18 -25.3333 -37 -38 -57 -38h-197c-10 0 -17 25 -21 75c148 0 228.667 1 242 3c14.6667 2.66666 22 14 22 34c0 14 -5.33333 38.6667 -16 74l14 19c7.33334 -29.3333 12.5 -52.8333 15.5 -70.5s8 -31.1667 15 -40.5
+s15.6667 -15.3333 26 -18s26.5 -4 48.5 -4c50.6667 0 76 14.3333 76 43c0 16.6667 -6 40.6667 -18 72l9 18c14 -42.6667 25.5 -73.1667 34.5 -91.5s17.5 -29.8333 25.5 -34.5s19.6667 -7 35 -7z" />
+ <glyph glyph-name="uniFEB5" unicode="&#x634;" horiz-adv-x="949" arabic-form="isolated"
+ d="M876 272c32.6667 0 49 6.66666 49 20c0 17.3333 -13 55 -39 113l23 36c29.3333 -66 44 -116.333 44 -151c0 -33.3333 -6.16669 -56.1667 -18.5 -68.5s-30.5 -18.5 -54.5 -18.5c-4.66669 -0.666672 -10.3333 -0.833328 -17 -0.5s-13.3333 1.16667 -20 2.5
+s-14.8333 4.5 -24.5 9.5s-19.5 11.8333 -29.5 20.5c-16.6667 -22 -36.3333 -33 -59 -33c-39.3333 0 -75 -0.333328 -107 -1c0 -36.6667 -3 -67.1667 -9 -91.5c-6 -24.3333 -16.5 -43.8333 -31.5 -58.5c-15 -14.6667 -28.3333 -25.1667 -40 -31.5
+c-11.6667 -6.33333 -30.1667 -14.5 -55.5 -24.5c-40 -16.6667 -89.6667 -25 -149 -25h-33c-17.3333 0.666666 -33 2.16667 -47 4.5s-29.8333 6.83333 -47.5 13.5c-17.6667 6.66667 -32.3333 15.1667 -44 25.5c-11.6667 10.3333 -21.6667 25 -30 44s-12.5 41.1667 -12.5 66.5
+c0 42 27 115.333 81 220l13 -23c-44 -67.3333 -66 -119 -66 -155v-2c0 -46.6667 9.5 -78.5 28.5 -95.5s51.5 -29.1667 97.5 -36.5c17.3333 -3.33333 38.3333 -5 63 -5c41.3333 0 85.3333 6.83333 132 20.5c46.6667 13.6667 74.3333 27.1667 83 40.5
+c19.3333 29.3333 29 69 29 119c0 46 -13.6667 84 -41 114l33 72c20 -37.3333 32.6667 -76.6667 38 -118h106c26.6667 0 40 22.6667 40 68v14l13 7c8 -36.6667 18 -61.1667 30 -73.5s36 -18.5 72 -18.5zM855 553l-47 -45l-49 45l49 45zM774 656l-47 -46l-49 46l49 44z
+M691 553l-47 -45l-49 45l49 45z" />
+ <glyph glyph-name="uniFEB6" unicode="&#x634;" horiz-adv-x="949" arabic-form="terminal"
+ d="M876 272c32.6667 0 49 6.66666 49 20c0 17.3333 -13 55 -39 113l23 36c29.3333 -66 44 -116.333 44 -151c0 -33.3333 -6.16669 -56.1667 -18.5 -68.5s-30.5 -18.5 -54.5 -18.5c-4.66669 -0.666672 -10.3333 -0.833328 -17 -0.5s-13.3333 1.16667 -20 2.5
+s-14.8333 4.5 -24.5 9.5s-19.5 11.8333 -29.5 20.5c-16.6667 -22 -36.3333 -33 -59 -33c-39.3333 0 -75 -0.333328 -107 -1c0 -36.6667 -3 -67.1667 -9 -91.5c-6 -24.3333 -16.5 -43.8333 -31.5 -58.5c-15 -14.6667 -28.3333 -25.1667 -40 -31.5
+c-11.6667 -6.33333 -30.1667 -14.5 -55.5 -24.5c-40 -16.6667 -89.6667 -25 -149 -25h-33c-17.3333 0.666666 -33 2.16667 -47 4.5s-29.8333 6.83333 -47.5 13.5c-17.6667 6.66667 -32.3333 15.1667 -44 25.5c-11.6667 10.3333 -21.6667 25 -30 44s-12.5 41.1667 -12.5 66.5
+c0 42 27 115.333 81 220l13 -23c-44 -67.3333 -66 -119 -66 -155v-2c0 -46.6667 9.5 -78.5 28.5 -95.5s51.5 -29.1667 97.5 -36.5c17.3333 -3.33333 38.3333 -5 63 -5c41.3333 0 85.3333 6.83333 132 20.5c46.6667 13.6667 74.3333 27.1667 83 40.5
+c19.3333 29.3333 29 69 29 119c0 46 -13.6667 84 -41 114l33 72c20 -37.3333 32.6667 -76.6667 38 -118h106c26.6667 0 40 22.6667 40 68v14l13 7c8 -36.6667 18 -61.1667 30 -73.5s36 -18.5 72 -18.5zM855 553l-47 -45l-49 45l49 45zM774 656l-47 -46l-49 46l49 44z
+M691 553l-47 -45l-49 45l49 45z" />
+ <glyph glyph-name="uniFEB7" unicode="&#x634;" horiz-adv-x="649" arabic-form="initial"
+ d="M570 280c21.3333 0 37.3333 2 48 6s16 12.6667 16 26c0 20 -19 59.3333 -57 118l24 60c42 -58.6667 63 -104.333 63 -137v-91c0 -26 -4.16669 -42.6667 -12.5 -50s-28.5 -11 -60.5 -11c-32.6667 0 -60 13.6667 -82 41c-24 -27.3333 -45 -41 -63 -41h-91
+c-20.6667 0 -41 13.6667 -61 41c-19.3333 -27.3333 -40 -41 -62 -41h-215c-10.6667 0 -18.3333 27.3333 -23 82c162 0 250 1 264 3c16 2.66666 24 15.3333 24 38c0 19.3333 -5.66666 46 -17 80l14 21c8.66666 -32.6667 14.5 -58.5 17.5 -77.5s8.5 -33.5 16.5 -43.5
+s17.5 -16.5 28.5 -19.5s28.8333 -4.5 53.5 -4.5c55.3333 0 83 16 83 48c0 17.3333 -6.66666 43.3333 -20 78l10 19c20 -62.6667 35.3333 -102.5 46 -119.5c10.6667 -17 29.3333 -25.5 56 -25.5zM585 648l-55 -53l-56 53l56 51zM491 767l-55 -53l-56 53l56 51zM395 648
+l-54 -53l-57 53l57 51z" />
+ <glyph glyph-name="uniFEB8" unicode="&#x634;" horiz-adv-x="649" arabic-form="medial"
+ d="M570 280c21.3333 0 37.3333 2 48 6s16 12.6667 16 26c0 20 -19 59.3333 -57 118l24 60c42 -58.6667 63 -104.333 63 -137v-91c0 -26 -4.16669 -42.6667 -12.5 -50s-28.5 -11 -60.5 -11c-32.6667 0 -60 13.6667 -82 41c-24 -27.3333 -45 -41 -63 -41h-91
+c-20.6667 0 -41 13.6667 -61 41c-19.3333 -27.3333 -40 -41 -62 -41h-215c-10.6667 0 -18.3333 27.3333 -23 82c162 0 250 1 264 3c16 2.66666 24 15.3333 24 38c0 19.3333 -5.66666 46 -17 80l14 21c8.66666 -32.6667 14.5 -58.5 17.5 -77.5s8.5 -33.5 16.5 -43.5
+s17.5 -16.5 28.5 -19.5s28.8333 -4.5 53.5 -4.5c55.3333 0 83 16 83 48c0 17.3333 -6.66666 43.3333 -20 78l10 19c20 -62.6667 35.3333 -102.5 46 -119.5c10.6667 -17 29.3333 -25.5 56 -25.5zM585 648l-55 -53l-56 53l56 51zM491 767l-55 -53l-56 53l56 51zM395 648
+l-54 -53l-57 53l57 51z" />
+ <glyph glyph-name="uniFEB9" unicode="&#x635;" horiz-adv-x="949" arabic-form="isolated"
+ d="M832 466c13.3333 0 26 -1.66666 38 -5s24.3333 -9.33334 37 -18s22.6667 -22.3333 30 -41s11 -41 11 -67c0 -22 -2.33331 -44.3333 -7 -67l-15 -34v-1c0 -20.6667 -62.3333 -31 -187 -31l-150 -1c-0.666687 -44.6667 -7.16669 -82.1667 -19.5 -112.5
+c-12.3333 -30.3333 -30.3333 -53.3333 -54 -69c-23.6667 -15.6667 -49.1667 -26.6667 -76.5 -33c-27.3333 -6.33333 -59.6667 -9.5 -97 -9.5c-141.333 0 -212 59 -212 177c2.66667 74 14.3333 139.667 35 197l18 -6c-18.6667 -52.6667 -28 -103.333 -28 -152
+c0 -50.6667 13.5 -89.8333 40.5 -117.5c27 -27.6667 76.1667 -42.5 147.5 -44.5c43.3333 1.33333 80.3333 7.5 111 18.5s53.5 25.1667 68.5 42.5s25.6667 34.8333 32 52.5c6.33331 17.6667 9.5 36.5 9.5 56.5c0 47.3333 -21 95.3333 -63 144l34 72
+c29.3333 -70 49 -113.667 59 -131l120 120c38.6667 36.6667 74.3333 56.6667 107 60h11zM895 323c0 54.6667 -28 82 -84 82c-54.6667 0 -115.667 -43.6667 -183 -131c4 0 10.3333 -0.166656 19 -0.5s15.3333 -0.5 20 -0.5c19.3333 0 74 1.66666 164 5
+c42.6667 11.3333 64 26.3333 64 45z" />
+ <glyph glyph-name="uniFEBA" unicode="&#x635;" horiz-adv-x="949" arabic-form="terminal"
+ d="M832 466c13.3333 0 26 -1.66666 38 -5s24.3333 -9.33334 37 -18s22.6667 -22.3333 30 -41s11 -41 11 -67c0 -22 -2.33331 -44.3333 -7 -67l-15 -34v-1c0 -20.6667 -62.3333 -31 -187 -31l-150 -1c-0.666687 -44.6667 -7.16669 -82.1667 -19.5 -112.5
+c-12.3333 -30.3333 -30.3333 -53.3333 -54 -69c-23.6667 -15.6667 -49.1667 -26.6667 -76.5 -33c-27.3333 -6.33333 -59.6667 -9.5 -97 -9.5c-141.333 0 -212 59 -212 177c2.66667 74 14.3333 139.667 35 197l18 -6c-18.6667 -52.6667 -28 -103.333 -28 -152
+c0 -50.6667 13.5 -89.8333 40.5 -117.5c27 -27.6667 76.1667 -42.5 147.5 -44.5c43.3333 1.33333 80.3333 7.5 111 18.5s53.5 25.1667 68.5 42.5s25.6667 34.8333 32 52.5c6.33331 17.6667 9.5 36.5 9.5 56.5c0 47.3333 -21 95.3333 -63 144l34 72
+c29.3333 -70 49 -113.667 59 -131l120 120c38.6667 36.6667 74.3333 56.6667 107 60h11zM895 323c0 54.6667 -28 82 -84 82c-54.6667 0 -115.667 -43.6667 -183 -131c4 0 10.3333 -0.166656 19 -0.5s15.3333 -0.5 20 -0.5c19.3333 0 74 1.66666 164 5
+c42.6667 11.3333 64 26.3333 64 45z" />
+ <glyph glyph-name="uniFEBB" unicode="&#x635;" horiz-adv-x="823" arabic-form="initial"
+ d="M724 492c74 -2 114.333 -64.6667 121 -188c0 -69.3333 -14.3333 -104 -43 -104h-416c-32 0 -65 16 -99 48c-31.3333 -32 -62.6667 -48 -94 -48h-169c-16 1.33333 -24 25.3333 -24 72h193c15.3333 10 27.5 19.5 36.5 28.5s15.5 20 19.5 33s6.33333 23.1667 7 30.5
+c0.666656 7.33334 1.33334 21 2 41l22 22c30 -103.333 78.6667 -155 146 -155h6c55.3333 83.3333 103.833 140.167 145.5 170.5s90.5 46.8333 146.5 49.5zM777 340c0 45.3333 -27.3333 72 -82 80c-30 -2.66666 -57.5 -9.33334 -82.5 -20s-46.6667 -25 -65 -43
+s-31.8333 -32.5 -40.5 -43.5c-8.66666 -11 -18.3333 -24.8333 -29 -41.5h263c24 12 36 34.6667 36 68z" />
+ <glyph glyph-name="uniFEBC" unicode="&#x635;" horiz-adv-x="823" arabic-form="medial"
+ d="M724 492c74 -2 114.333 -64.6667 121 -188c0 -69.3333 -14.3333 -104 -43 -104h-416c-32 0 -65 16 -99 48c-31.3333 -32 -62.6667 -48 -94 -48h-169c-16 1.33333 -24 25.3333 -24 72h193c15.3333 10 27.5 19.5 36.5 28.5s15.5 20 19.5 33s6.33333 23.1667 7 30.5
+c0.666656 7.33334 1.33334 21 2 41l22 22c30 -103.333 78.6667 -155 146 -155h6c55.3333 83.3333 103.833 140.167 145.5 170.5s90.5 46.8333 146.5 49.5zM777 340c0 45.3333 -27.3333 72 -82 80c-30 -2.66666 -57.5 -9.33334 -82.5 -20s-46.6667 -25 -65 -43
+s-31.8333 -32.5 -40.5 -43.5c-8.66666 -11 -18.3333 -24.8333 -29 -41.5h263c24 12 36 34.6667 36 68z" />
+ <glyph glyph-name="uniFEBD" unicode="&#x636;" horiz-adv-x="949" arabic-form="isolated"
+ d="M832 466c13.3333 0 26 -1.66666 38 -5s24.3333 -9.33334 37 -18s22.6667 -22.3333 30 -41s11 -41 11 -67c0 -22 -2.33331 -44.3333 -7 -67l-15 -34v-1c0 -20.6667 -62.3333 -31 -187 -31l-150 -1c-0.666687 -44.6667 -7.16669 -82.1667 -19.5 -112.5
+c-12.3333 -30.3333 -30.3333 -53.3333 -54 -69c-23.6667 -15.6667 -49.1667 -26.6667 -76.5 -33c-27.3333 -6.33333 -59.6667 -9.5 -97 -9.5c-141.333 0 -212 59 -212 177c2.66667 74 14.3333 139.667 35 197l18 -6c-18.6667 -52.6667 -28 -103.333 -28 -152
+c0 -50.6667 13.5 -89.8333 40.5 -117.5c27 -27.6667 76.1667 -42.5 147.5 -44.5c43.3333 1.33333 80.3333 7.5 111 18.5s53.5 25.1667 68.5 42.5s25.6667 34.8333 32 52.5c6.33331 17.6667 9.5 36.5 9.5 56.5c0 47.3333 -21 95.3333 -63 144l34 72
+c29.3333 -70 49 -113.667 59 -131l120 120c38.6667 36.6667 74.3333 56.6667 107 60h11zM895 333c0 54.6667 -28 82 -84 82c-54.6667 0 -115.667 -43.6667 -183 -131c4 0 10.3333 -0.166656 19 -0.5s15.3333 -0.5 20 -0.5c19.3333 0 74 1.66666 164 5
+c42.6667 11.3333 64 26.3333 64 45zM747 633l-49 -48l-48 48l48 48z" />
+ <glyph glyph-name="uniFEBE" unicode="&#x636;" horiz-adv-x="949" arabic-form="terminal"
+ d="M832 466c13.3333 0 26 -1.66666 38 -5s24.3333 -9.33334 37 -18s22.6667 -22.3333 30 -41s11 -41 11 -67c0 -22 -2.33331 -44.3333 -7 -67l-15 -34v-1c0 -20.6667 -62.3333 -31 -187 -31l-150 -1c-0.666687 -44.6667 -7.16669 -82.1667 -19.5 -112.5
+c-12.3333 -30.3333 -30.3333 -53.3333 -54 -69c-23.6667 -15.6667 -49.1667 -26.6667 -76.5 -33c-27.3333 -6.33333 -59.6667 -9.5 -97 -9.5c-141.333 0 -212 59 -212 177c2.66667 74 14.3333 139.667 35 197l18 -6c-18.6667 -52.6667 -28 -103.333 -28 -152
+c0 -50.6667 13.5 -89.8333 40.5 -117.5c27 -27.6667 76.1667 -42.5 147.5 -44.5c43.3333 1.33333 80.3333 7.5 111 18.5s53.5 25.1667 68.5 42.5s25.6667 34.8333 32 52.5c6.33331 17.6667 9.5 36.5 9.5 56.5c0 47.3333 -21 95.3333 -63 144l34 72
+c29.3333 -70 49 -113.667 59 -131l120 120c38.6667 36.6667 74.3333 56.6667 107 60h11zM895 333c0 54.6667 -28 82 -84 82c-54.6667 0 -115.667 -43.6667 -183 -131c4 0 10.3333 -0.166656 19 -0.5s15.3333 -0.5 20 -0.5c19.3333 0 74 1.66666 164 5
+c42.6667 11.3333 64 26.3333 64 45zM747 633l-49 -48l-48 48l48 48z" />
+ <glyph glyph-name="uniFEBF" unicode="&#x636;" horiz-adv-x="805" arabic-form="initial"
+ d="M608 704l-49 -48l-48 48l48 48zM791 443c22.6667 -48 34 -94.3333 34 -139c0 -69.3333 -14.3333 -104 -43 -104h-416c-32 0 -65 16 -99 48c-31.3333 -32 -62.6667 -48 -94 -48h-169c-16 1.33333 -24 28.6667 -24 82h193c23.3333 8 39.6667 19.6667 49 35
+s14.6667 44.6667 16 88l22 22c28 -97.3333 72.6667 -146 134 -146c8 0 14 0.333344 18 1c58 78.6667 107.167 132.667 147.5 162s88.5 45.3333 144.5 48c34 -2 63 -18.3333 87 -49zM757 341c0 44.6667 -27.3333 70.6667 -82 78c-82.6667 -6 -155 -51.6667 -217 -137h263
+c24 6 36 25.6667 36 59z" />
+ <glyph glyph-name="uniFEC0" unicode="&#x636;" horiz-adv-x="805" arabic-form="medial"
+ d="M608 704l-49 -48l-48 48l48 48zM791 443c22.6667 -48 34 -94.3333 34 -139c0 -69.3333 -14.3333 -104 -43 -104h-416c-32 0 -65 16 -99 48c-31.3333 -32 -62.6667 -48 -94 -48h-169c-16 1.33333 -24 28.6667 -24 82h193c23.3333 8 39.6667 19.6667 49 35
+s14.6667 44.6667 16 88l22 22c28 -97.3333 72.6667 -146 134 -146c8 0 14 0.333344 18 1c58 78.6667 107.167 132.667 147.5 162s88.5 45.3333 144.5 48c34 -2 63 -18.3333 87 -49zM757 341c0 44.6667 -27.3333 70.6667 -82 78c-82.6667 -6 -155 -51.6667 -217 -137h263
+c24 6 36 25.6667 36 59z" />
+ <glyph glyph-name="uniFEC1" unicode="&#x637;" horiz-adv-x="557" arabic-form="isolated"
+ d="M165 277c14 11.3333 21 23.6667 21 37c0 87.3333 -28.6667 216 -86 386l63 83l26.5 -146c9.66667 -51.3333 18.5 -107 26.5 -167s12 -107 12 -141c0 -2.66666 -0.166672 -6.5 -0.5 -11.5s-0.5 -8.5 -0.5 -10.5c77.3333 87.3333 150 131 218 131
+c33.3333 0 62.1667 -11 86.5 -33c24.3333 -22 36.5 -61.6667 36.5 -119v-4c0 -54 -20.3333 -81 -61 -81h-513l-1 79zM537 304c0 30 -9.66669 51.5 -29 64.5c-19.3333 13 -41 19.5 -65 19.5c-27.3333 0 -57.3333 -9.83334 -90 -29.5s-58.3333 -37.8333 -77 -54.5l-20 -20h279
+c1.33331 9.33334 2 16 2 20z" />
+ <glyph glyph-name="uniFEC5" unicode="&#x638;" horiz-adv-x="550" arabic-form="isolated"
+ d="M443 612l-46 -46l-47 46l47 47zM165 277c14 11.3333 21 23.6667 21 37c0 87.3333 -28.6667 216 -86 386l63 83l26.5 -146c9.66667 -51.3333 18.5 -107 26.5 -167s12 -107 12 -141c0 -2.66666 -0.166672 -6.5 -0.5 -11.5s-0.5 -8.5 -0.5 -10.5
+c77.3333 87.3333 150 131 218 131c33.3333 0 62.1667 -11 86.5 -33c24.3333 -22 36.5 -61.6667 36.5 -119v-4c0 -54 -20.3333 -81 -61 -81h-513l-1 79zM537 304c0 30 -9.66669 51.5 -29 64.5c-19.3333 13 -41 19.5 -65 19.5c-27.3333 0 -57.3333 -9.83334 -90 -29.5
+s-58.3333 -37.8333 -77 -54.5l-20 -20h279c1.33331 9.33334 2 16 2 20z" />
+ <glyph glyph-name="uniFEC9" unicode="&#x639;" horiz-adv-x="625" arabic-form="isolated"
+ d="M130 -67c0 34.6667 10.3333 76.8333 31 126.5c20.6667 49.6667 51.6667 91.8333 93 126.5c-58 50 -98.6667 89 -122 117v32c0 40.6667 21.6667 80 65 118c37.3333 32.6667 79.3333 49 126 49h5c35.3333 -5.33334 75.6667 -22 121 -50c-8.66666 0.666656 -21 1 -37 1
+c-51.3333 0 -102.667 -9.33334 -154 -28c-51.3333 -18.6667 -79.6667 -36.6667 -85 -54c1.33333 -24 18.3333 -49.6667 51 -77c32.6667 -27.3333 64.3333 -41 95 -41h6c80 38.6667 158 61 234 67l-35 -67c-94.6667 -10 -167.667 -40 -219 -90
+c-87.3333 -83.3333 -131 -148.333 -131 -195c0 -50.6667 120.333 -91.3333 361 -122h111l-104 -65c-149.333 7.33333 -261.667 22 -337 44c-50 14 -75 50 -75 108z" />
+ <glyph glyph-name="uniFECA" unicode="&#x639;" horiz-adv-x="575" arabic-form="terminal"
+ d="M359 536c8 -0.666687 16.3333 -2 25 -4s18.6667 -5.33331 30 -10s20.6667 -11.6667 28 -21s11 -20.3333 11 -33c0 -21.3333 -12.6667 -45 -38 -71c-16.6667 -8 -37.6667 -23 -63 -45c10.6667 -50.6667 49.3333 -76 116 -76h131l5 -76h-134
+c-68 11.3333 -119.333 46.6667 -154 106c-49.3333 -36 -87 -73 -113 -111s-39 -80.6667 -39 -128c0 -28 8.83333 -52.6667 26.5 -74c17.6667 -21.3333 39.5 -37 65.5 -47s49.8333 -17.3333 71.5 -22s40.1667 -7 55.5 -7c34 0 75.6667 14 125 42l43 -51
+c-69.3333 -37.3333 -130.667 -56 -184 -56c-69.3333 0 -127.167 20.1667 -173.5 60.5c-46.3333 40.3333 -69.5 93.1667 -69.5 158.5c0 42.6667 9.16667 83.8333 27.5 123.5s39.1667 72.6667 62.5 99s55.6667 58.5 97 96.5c-1.33334 4 -2.5 7.83334 -3.5 11.5
+s-2.33334 7.16666 -4 10.5s-3.33334 6.33334 -5 9s-4 4.66666 -7 6s-6.16666 2 -9.5 2c-0.666656 0 -1.66666 -0.166656 -3 -0.5s-2.33334 -0.5 -3 -0.5l-61 -11c2 79.3333 50 119 144 119z" />
+ <glyph glyph-name="uniFECB" unicode="&#x639;" horiz-adv-x="674" arabic-form="initial"
+ d="M257 429c0 -24 14.3333 -51.3333 43 -82s62.3333 -46 101 -46c67.3333 0 158 8.66666 272 26l-50 -77c-116 -32.6667 -234 -49 -354 -49h-252c-16 0 -24 25.3333 -24 76l276 -1c-42.6667 63.3333 -64 114.333 -64 153c8 35.3333 27.8333 65.1667 59.5 89.5
+c31.6667 24.3333 66.8333 36.5 105.5 36.5l56 -5c58 -26 98.3333 -50.3333 121 -73c-64 10.6667 -114 16 -150 16c-34 0 -65.8333 -6.16666 -95.5 -18.5s-44.5 -27.5 -44.5 -45.5z" />
+ <glyph glyph-name="uniFECC" unicode="&#x639;" horiz-adv-x="550" arabic-form="medial"
+ d="M346 528c37.3333 0 68.6667 -6.66669 94 -20c25.3333 -13.3333 38 -30.6667 38 -52v-1c0 -24.6667 -24 -63.3333 -72 -116c24 -41.3333 52.6667 -62 86 -62h2h74v-77h-76c-48 0 -92.3333 31 -133 93c-54 -62 -112.667 -93 -176 -93h-2l-167 -1
+c-14.6667 0.666672 -22.6667 26.6667 -24 78l144 1c3.33333 0 8.33333 -0.166656 15 -0.5s11.3333 -0.5 14 -0.5c101.333 0 152 29.6667 152 89c0 4 -1.33334 9.16666 -4 15.5s-8.66666 13 -18 20s-21 10.5 -35 10.5c-7.33333 0 -14.5 -3 -21.5 -9s-11.5 -14.6667 -13.5 -26
+h-9v22c2 41.3333 14 73.1667 36 95.5c22 22.3333 54 33.5 96 33.5z" />
+ <glyph glyph-name="uniFECD" unicode="&#x63a;" horiz-adv-x="602" arabic-form="isolated"
+ d="M130 -62c0 40 10.8333 83.8333 32.5 131.5c21.6667 47.6667 51.8333 87.5 90.5 119.5c-58 49.3333 -98.3333 88 -121 116v29v3c0 40.6667 21.6667 80 65 118c36.6667 32 78 48 124 48h4c34.6667 -5.33334 75 -21.6667 121 -49c-7.33334 0.666656 -18 1 -32 1
+c-51.3333 0 -103.167 -9.5 -155.5 -28.5c-52.3333 -19 -81.1667 -36.8333 -86.5 -53.5c2.66667 -24 19.8333 -49.5 51.5 -76.5s62.8333 -40.5 93.5 -40.5h6c79.3333 38.6667 156.333 60.6667 231 66l-35 -66c-95.3333 -10 -167.333 -39.6667 -216 -89
+c-86 -80.6667 -129 -145 -129 -193c0 -50.6667 118.667 -91 356 -121h110l-103 -65c-146 7.33333 -257 22 -333 44c-49.3333 14.6667 -74 50 -74 106zM323 720l-48 -48l-49 48l49 48z" />
+ <glyph glyph-name="uniFECE" unicode="&#x63a;" horiz-adv-x="577" arabic-form="terminal"
+ d="M394 674l-49 -50l-50 50l50 49zM359 536c8 -0.666687 16.3333 -2 25 -4s18.6667 -5.33331 30 -10s20.6667 -11.6667 28 -21s11 -20.3333 11 -33c0 -21.3333 -12.6667 -45 -38 -71c-16.6667 -8 -37.6667 -23 -63 -45c10.6667 -50.6667 49.3333 -76 116 -76h131l5 -76h-134
+c-68 11.3333 -119.333 46.6667 -154 106c-49.3333 -36 -87 -73 -113 -111s-39 -80.6667 -39 -128c0 -28 8.83333 -52.6667 26.5 -74c17.6667 -21.3333 39.5 -37 65.5 -47s49.8333 -17.3333 71.5 -22s40.1667 -7 55.5 -7c34 0 75.6667 14 125 42l43 -51
+c-69.3333 -37.3333 -130.667 -56 -184 -56c-69.3333 0 -127.167 20.1667 -173.5 60.5c-46.3333 40.3333 -69.5 93.1667 -69.5 158.5c0 42.6667 9.16667 83.8333 27.5 123.5s39.1667 72.6667 62.5 99s55.6667 58.5 97 96.5c-1.33334 4 -2.5 7.83334 -3.5 11.5
+s-2.33334 7.16666 -4 10.5s-3.33334 6.33334 -5 9s-4 4.66666 -7 6s-6.16666 2 -9.5 2c-0.666656 0 -1.66666 -0.166656 -3 -0.5s-2.33334 -0.5 -3 -0.5l-61 -11c2 79.3333 50 119 144 119z" />
+ <glyph glyph-name="uniFECF" unicode="&#x63a;" horiz-adv-x="578" arabic-form="initial"
+ d="M222 420c0 -20 12.3333 -45.5 37 -76.5c24.6667 -31 56 -46.5 94 -46.5c62 0 144.333 8.66666 247 26l-46 -74c-106 -32 -212.667 -48 -320 -48h-229c-14.6667 0 -22 24.3333 -22 73l251 -1c-39.3333 62.6667 -59 112 -59 148c8 34 26.3333 62.6667 55 86
+c28.6667 23.3333 60.3333 35 95 35l51 -5c51.3333 -24 87.6667 -47.3333 109 -70c-52.6667 10 -97.6667 15 -135 15c-30 0 -58.8333 -5.83334 -86.5 -17.5c-27.6667 -11.6667 -41.5 -26.5 -41.5 -44.5zM368 753l-46 -48l-46 48l46 49z" />
+ <glyph glyph-name="uniFED0" unicode="&#x63a;" horiz-adv-x="577" arabic-form="medial"
+ d="M355 522c39.3333 0 71.6667 -6.66669 97 -20c25.3333 -13.3333 38 -30.3333 38 -51v-3c0 -24 -24.6667 -61.3333 -74 -112c25.3333 -40 54.6667 -60 88 -60h2h97v-76h-98c-49.3333 0 -95 30 -137 90c-54.6667 -60 -114.667 -90 -180 -90h-2l-171 -1
+c-16 1.33333 -24.3333 27 -25 77l147 1c8 -0.666656 19.3333 -1 34 -1c101.333 0 152 29 152 87c0 8 -5 17.6667 -15 29s-24.6667 17 -44 17c-7.33334 0 -14.5 -3.16666 -21.5 -9.5s-11.5 -15.1667 -13.5 -26.5h-9v23c2 40.6667 14.3333 71.8333 37 93.5
+c22.6667 21.6667 55.3333 32.5 98 32.5zM397 703l-49 -50l-49 50l49 50z" />
+ <glyph glyph-name="uniFED1" unicode="&#x641;" horiz-adv-x="801" arabic-form="isolated"
+ d="M789 521c14.6667 -64 22 -116.667 22 -158v-66c0 -61.3333 -28.6667 -92 -86 -92l-526 1c-16 2 -28.6667 5.66667 -38 11s-16.3333 14 -21 26s-7.66667 24.1667 -9 36.5s-2.33333 30.1667 -3 53.5c1.33333 36 10 79.3333 26 130l26 -27c-22.6667 -52 -34 -90 -34 -114
+c0 -22.6667 11.3333 -36.3333 34 -41c55.3333 -0.666656 138.333 -1 249 -1c27.3333 0 68.6667 0.166656 124 0.5c55.3333 0.333344 96.6667 0.5 124 0.5h5c55.3333 0 83 16 83 48v5c-38.6667 8.66666 -70.6667 15.5 -96 20.5s-44.5 13.5 -57.5 25.5s-19.5 29.6667 -19.5 53
+c0 42.6667 11 84.6667 33 126c16 38 39.3333 57 70 57h4c30.6667 0 60.6667 -31.6667 90 -95zM693 529c-24 -6.66669 -36 -30.3333 -36 -71c0 -32.6667 28 -49 84 -49c10 0 17.6667 0.333344 23 1v1c-5.33331 26 -14.5 51.3333 -27.5 76s-27.5 38.6667 -43.5 42zM675 712
+l-49 -50l-50 50l50 51z" />
+ <glyph glyph-name="uniFED2" unicode="&#x641;" horiz-adv-x="801" arabic-form="terminal"
+ d="M789 521c14.6667 -64 22 -116.667 22 -158v-66c0 -61.3333 -28.6667 -92 -86 -92l-526 1c-16 2 -28.6667 5.66667 -38 11s-16.3333 14 -21 26s-7.66667 24.1667 -9 36.5s-2.33333 30.1667 -3 53.5c1.33333 36 10 79.3333 26 130l26 -27c-22.6667 -52 -34 -90 -34 -114
+c0 -22.6667 11.3333 -36.3333 34 -41c55.3333 -0.666656 138.333 -1 249 -1c27.3333 0 68.6667 0.166656 124 0.5c55.3333 0.333344 96.6667 0.5 124 0.5h5c55.3333 0 83 16 83 48v5c-38.6667 8.66666 -70.6667 15.5 -96 20.5s-44.5 13.5 -57.5 25.5s-19.5 29.6667 -19.5 53
+c0 42.6667 11 84.6667 33 126c16 38 39.3333 57 70 57h4c30.6667 0 60.6667 -31.6667 90 -95zM693 529c-24 -6.66669 -36 -30.3333 -36 -71c0 -32.6667 28 -49 84 -49c10 0 17.6667 0.333344 23 1v1c-5.33331 26 -14.5 51.3333 -27.5 76s-27.5 38.6667 -43.5 42zM675 712
+l-49 -50l-50 50l50 51z" />
+ <glyph glyph-name="uniFED3" unicode="&#x641;" arabic-form="initial"
+ d="M296 509c14.6667 -44 22 -95.3333 22 -154v-63c0 -61.3333 -27.6667 -92 -83 -92h-265v74l218 1h5c53.3333 0 80 15.6667 80 47v5c-35.3333 8.66666 -65.5 15.3333 -90.5 20s-44 12.8333 -57 24.5s-19.5 28.8333 -19.5 51.5c0 44 10.6667 85 32 123
+c15.3333 37.3333 38 56 68 56h4c16 0 31.6667 -7.83331 47 -23.5c15.3333 -15.6667 28.3333 -38.8333 39 -69.5zM197 753l-49 -50l-48 50l48 50zM196 527c-13.3333 0 -25.6667 -8.33331 -37 -25c-11.3333 -16.6667 -17 -33 -17 -49c0 -9.33334 1.5 -17.6667 4.5 -25
+s7.5 -13.1667 13.5 -17.5s12.8333 -8 20.5 -11s16.5 -5.33334 26.5 -7s20.5 -3.16666 31.5 -4.5s22.5 -2.33334 34.5 -3c-2.66666 22 -7 43 -13 63s-14.6667 38.1667 -26 54.5c-11.3333 16.3333 -24 24.5 -38 24.5z" />
+ <glyph glyph-name="uniFED4" unicode="&#x641;" arabic-form="medial"
+ d="M296 509c14.6667 -44 22 -95.3333 22 -154v-63c0 -61.3333 -27.6667 -92 -83 -92h-265v74l218 1h5c53.3333 0 80 15.6667 80 47v5c-35.3333 8.66666 -65.5 15.3333 -90.5 20s-44 12.8333 -57 24.5s-19.5 28.8333 -19.5 51.5c0 44 10.6667 85 32 123
+c15.3333 37.3333 38 56 68 56h4c16 0 31.6667 -7.83331 47 -23.5c15.3333 -15.6667 28.3333 -38.8333 39 -69.5zM197 753l-49 -50l-48 50l48 50zM196 527c-13.3333 0 -25.6667 -8.33331 -37 -25c-11.3333 -16.6667 -17 -33 -17 -49c0 -9.33334 1.5 -17.6667 4.5 -25
+s7.5 -13.1667 13.5 -17.5s12.8333 -8 20.5 -11s16.5 -5.33334 26.5 -7s20.5 -3.16666 31.5 -4.5s22.5 -2.33334 34.5 -3c-2.66666 22 -7 43 -13 63s-14.6667 38.1667 -26 54.5c-11.3333 16.3333 -24 24.5 -38 24.5z" />
+ <glyph glyph-name="uniFED5" unicode="&#x642;" horiz-adv-x="696" arabic-form="isolated"
+ d="M709 562l-55 -55l-55 55l55 55zM552 562l-56 -55l-55 55l55 55zM606 417c24 -10.6667 48 -30.1667 72 -58.5s37.6667 -65.8333 41 -112.5v-63c-11.3333 -95.3333 -40.6667 -157.667 -88 -187c-60.6667 -37.3333 -147 -56 -259 -56h-31c-139.333 30 -209 84.3333 -209 163
+c0 3.33334 -0.333328 9 -1 17s-1 14 -1 18c0 64 17 136.667 51 218h11c-18.6667 -68.6667 -28 -124.667 -28 -168c0 -26 3.16667 -47.8333 9.5 -65.5c6.33333 -17.6667 18.8333 -34.3333 37.5 -50c18.6667 -15.6667 47 -27.3333 85 -35c38 -7.66667 86.3333 -11.5 145 -11.5
+c16.6667 0 43.1667 4.16667 79.5 12.5c36.3333 8.33333 64.8333 16.1667 85.5 23.5c50 24 75 61 75 111c0 13.3333 -2 22.5 -6 27.5s-12.6667 7.5 -26 7.5c-11.3333 0 -27.6667 -2.66667 -49 -8c-63.3333 0 -95 17 -95 51c0 31.3333 10.8333 65.6667 32.5 103
+s44.5 58.3333 68.5 63zM605 354c-16.6667 0 -30 -7.83334 -40 -23.5s-15 -28.5 -15 -38.5c0 -13.3333 13.6667 -20 41 -20h9c25.3333 0 40 0.666656 44 2c3.33331 0 5 3 5 9c0 16.6667 -6 32.6667 -18 48l-24 23h-2z" />
+ <glyph glyph-name="uniFED6" unicode="&#x642;" horiz-adv-x="696" arabic-form="terminal"
+ d="M709 562l-55 -55l-55 55l55 55zM552 562l-56 -55l-55 55l55 55zM606 417c24 -10.6667 48 -30.1667 72 -58.5s37.6667 -65.8333 41 -112.5v-63c-11.3333 -95.3333 -40.6667 -157.667 -88 -187c-60.6667 -37.3333 -147 -56 -259 -56h-31c-139.333 30 -209 84.3333 -209 163
+c0 3.33334 -0.333328 9 -1 17s-1 14 -1 18c0 64 17 136.667 51 218h11c-18.6667 -68.6667 -28 -124.667 -28 -168c0 -26 3.16667 -47.8333 9.5 -65.5c6.33333 -17.6667 18.8333 -34.3333 37.5 -50c18.6667 -15.6667 47 -27.3333 85 -35c38 -7.66667 86.3333 -11.5 145 -11.5
+c16.6667 0 43.1667 4.16667 79.5 12.5c36.3333 8.33333 64.8333 16.1667 85.5 23.5c50 24 75 61 75 111c0 13.3333 -2 22.5 -6 27.5s-12.6667 7.5 -26 7.5c-11.3333 0 -27.6667 -2.66667 -49 -8c-63.3333 0 -95 17 -95 51c0 31.3333 10.8333 65.6667 32.5 103
+s44.5 58.3333 68.5 63zM605 354c-16.6667 0 -30 -7.83334 -40 -23.5s-15 -28.5 -15 -38.5c0 -13.3333 13.6667 -20 41 -20h9c25.3333 0 40 0.666656 44 2c3.33331 0 5 3 5 9c0 16.6667 -6 32.6667 -18 48l-24 23h-2z" />
+ <glyph glyph-name="uniFED7" unicode="&#x642;" horiz-adv-x="650" arabic-form="initial"
+ d="M292 503c14 -40.6667 21 -90.3333 21 -149v-62c0 -60 -27.3333 -90 -82 -90h-261v72l215 1h5c52.6667 0 79 15.3333 79 46v5c-34.6667 8 -64.1667 14 -88.5 18s-43.1667 11.8333 -56.5 23.5c-13.3333 11.6667 -20 29.1667 -20 52.5c0 36.6667 9.33334 74.8333 28 114.5
+c18.6667 39.6667 42 59.5 70 59.5h4c16 0 31.6667 -7.66669 47 -23c15.3333 -15.3333 28.3333 -38 39 -68zM147 744l-48 -50l-47 50l47 48zM139 447c0 -12.6667 3.16667 -23.1667 9.5 -31.5s16.3333 -14.6667 30 -19s26.6667 -7.33334 39 -9s29.5 -3.16666 51.5 -4.5
+c-4.66666 34 -13.5 65.3333 -26.5 94s-29.5 43 -49.5 43c-13.3333 0 -25.6667 -8.16666 -37 -24.5s-17 -32.5 -17 -48.5zM276 744l-47 -50l-48 50l48 48z" />
+ <glyph glyph-name="uniFED8" unicode="&#x642;" horiz-adv-x="650" arabic-form="medial"
+ d="M292 503c14 -40.6667 21 -90.3333 21 -149v-62c0 -60 -27.3333 -90 -82 -90h-261v72l215 1h5c52.6667 0 79 15.3333 79 46v5c-34.6667 8 -64.1667 14 -88.5 18s-43.1667 11.8333 -56.5 23.5c-13.3333 11.6667 -20 29.1667 -20 52.5c0 36.6667 9.33334 74.8333 28 114.5
+c18.6667 39.6667 42 59.5 70 59.5h4c16 0 31.6667 -7.66669 47 -23c15.3333 -15.3333 28.3333 -38 39 -68zM147 744l-48 -50l-47 50l47 48zM139 447c0 -12.6667 3.16667 -23.1667 9.5 -31.5s16.3333 -14.6667 30 -19s26.6667 -7.33334 39 -9s29.5 -3.16666 51.5 -4.5
+c-4.66666 34 -13.5 65.3333 -26.5 94s-29.5 43 -49.5 43c-13.3333 0 -25.6667 -8.16666 -37 -24.5s-17 -32.5 -17 -48.5zM276 744l-47 -50l-48 50l48 48z" />
+ <glyph glyph-name="uniFED9" unicode="&#x643;" horiz-adv-x="757" arabic-form="isolated"
+ d="M948 958l-199 -87c-12.6667 -5.33331 -37.1667 -16.5 -73.5 -33.5s-54.5 -27.8333 -54.5 -32.5c0 -5.33331 4.16669 -12.6667 12.5 -22s19.5 -20.8333 33.5 -34.5s35.1667 -37.8333 63.5 -72.5s58.1667 -74.6667 89.5 -120c26.6667 -42.6667 50 -103 70 -181
+c2.66669 -10 4 -35 4 -75c0 -67.3333 -14 -101 -42 -101h-1l-587 2c-52 0 -94.6667 29 -128 87c-10 16.6667 -15 46.3333 -15 89c0 44.6667 6.66666 88.3333 20 131l8 -4c-4.66667 -30 -7 -58.3333 -7 -85c0 -51.3333 13.1667 -88.3333 39.5 -111s72.1667 -34 137.5 -34h11
+h529c1.33331 16 2 27.6667 2 35c0 81.3333 -41.6667 176.667 -125 286l-61 65l-11 -14c-22.6667 15.3333 -51.3333 40.3333 -86 75c-2.66669 17.3333 -4 30 -4 38c0 18.6667 2.33331 35 7 49s12.5 27.3333 23.5 40s25.8333 24.5 44.5 35.5s42 23.3333 70 37
+s61.3333 28.3333 100 44l135 56.5z" />
+ <glyph glyph-name="uniFEDA" unicode="&#x643;" horiz-adv-x="757" arabic-form="terminal"
+ d="M948 958l-199 -87c-12.6667 -5.33331 -37.1667 -16.5 -73.5 -33.5s-54.5 -27.8333 -54.5 -32.5c0 -5.33331 4.16669 -12.6667 12.5 -22s19.5 -20.8333 33.5 -34.5s35.1667 -37.8333 63.5 -72.5s58.1667 -74.6667 89.5 -120c26.6667 -42.6667 50 -103 70 -181
+c2.66669 -10 4 -35 4 -75c0 -67.3333 -14 -101 -42 -101h-1l-587 2c-52 0 -94.6667 29 -128 87c-10 16.6667 -15 46.3333 -15 89c0 44.6667 6.66666 88.3333 20 131l8 -4c-4.66667 -30 -7 -58.3333 -7 -85c0 -51.3333 13.1667 -88.3333 39.5 -111s72.1667 -34 137.5 -34h11
+h529c1.33331 16 2 27.6667 2 35c0 81.3333 -41.6667 176.667 -125 286l-61 65l-11 -14c-22.6667 15.3333 -51.3333 40.3333 -86 75c-2.66669 17.3333 -4 30 -4 38c0 18.6667 2.33331 35 7 49s12.5 27.3333 23.5 40s25.8333 24.5 44.5 35.5s42 23.3333 70 37
+s61.3333 28.3333 100 44l135 56.5z" />
+ <glyph glyph-name="uniFEDB" unicode="&#x643;" horiz-adv-x="318" arabic-form="initial"
+ d="M388 912l-199 -82c-2.66667 -1.33331 -16.5 -7.16669 -41.5 -17.5s-45.6667 -19.5 -62 -27.5s-24.5 -13.6667 -24.5 -17c0 -5.33331 35.6667 -44.6667 107 -118c56.6667 -68 98.5 -127.833 125.5 -179.5c27 -51.6667 40.5 -110.5 40.5 -176.5c0 -63.3333 -14 -95 -42 -95
+h-1l-306 2l6 78h308c1.33334 13.3333 2 23 2 29c0 70.6667 -41.6667 158.333 -125 263l-61 61l-11 -13c-22.6667 14.6667 -51.3333 38 -86 70c-2.66667 16 -4 28 -4 36c0 20.6667 3.66667 38.5 11 53.5c7.33333 15 19 29.1667 35 42.5s39.3333 27.3333 70 42
+c30.6667 14.6667 65.8333 30 105.5 46l152.5 60l6 2z" />
+ <glyph glyph-name="uniFEDC" unicode="&#x643;" horiz-adv-x="318" arabic-form="medial"
+ d="M388 912l-199 -82c-2.66667 -1.33331 -16.5 -7.16669 -41.5 -17.5s-45.6667 -19.5 -62 -27.5s-24.5 -13.6667 -24.5 -17c0 -5.33331 35.6667 -44.6667 107 -118c56.6667 -68 98.5 -127.833 125.5 -179.5c27 -51.6667 40.5 -110.5 40.5 -176.5c0 -63.3333 -14 -95 -42 -95
+h-1l-306 2l6 78h308c1.33334 13.3333 2 23 2 29c0 70.6667 -41.6667 158.333 -125 263l-61 61l-11 -13c-22.6667 14.6667 -51.3333 38 -86 70c-2.66667 16 -4 28 -4 36c0 20.6667 3.66667 38.5 11 53.5c7.33333 15 19 29.1667 35 42.5s39.3333 27.3333 70 42
+c30.6667 14.6667 65.8333 30 105.5 46l152.5 60l6 2z" />
+ <glyph glyph-name="uniFEDD" unicode="&#x644;" horiz-adv-x="655" arabic-form="isolated"
+ d="M665 161c0 -56.6667 -3.83331 -103 -11.5 -139s-21.8333 -67.6667 -42.5 -95c-20.6667 -27.3333 -50 -47 -88 -59s-86.6667 -18 -146 -18c-163.333 0 -245 64.3333 -245 193c0 64.6667 20.3333 151.667 61 261l16 -6c-30.6667 -94 -46 -166 -46 -216
+c0 -49.3333 25.3333 -91.3333 76 -126c59.3333 -12.6667 113 -19 161 -19c54 0 92.6667 6 116 18c59.3333 30.6667 89 83 89 157c0 176 -12.3333 410.667 -37 704l38 38l52 41l47 -146l-52 -64v-48c0 -114.667 2 -218.5 6 -311.5s6 -147.833 6 -164.5z" />
+ <glyph glyph-name="uniFEDE" unicode="&#x644;" horiz-adv-x="655" arabic-form="terminal"
+ d="M665 161c0 -56.6667 -3.83331 -103 -11.5 -139s-21.8333 -67.6667 -42.5 -95c-20.6667 -27.3333 -50 -47 -88 -59s-86.6667 -18 -146 -18c-163.333 0 -245 64.3333 -245 193c0 64.6667 20.3333 151.667 61 261l16 -6c-30.6667 -94 -46 -166 -46 -216
+c0 -49.3333 25.3333 -91.3333 76 -126c59.3333 -12.6667 113 -19 161 -19c54 0 92.6667 6 116 18c59.3333 30.6667 89 83 89 157c0 176 -12.3333 410.667 -37 704l38 38l52 41l47 -146l-52 -64v-48c0 -114.667 2 -218.5 6 -311.5s6 -147.833 6 -164.5z" />
+ <glyph glyph-name="uniFEDF" unicode="&#x644;" horiz-adv-x="206" arabic-form="initial"
+ d="M210 901l40 -130l-40 9v-391c0 -49.3333 -4.5 -87.3333 -13.5 -114c-9 -26.6667 -21 -44.5 -36 -53.5s-36.8333 -15.8333 -65.5 -20.5l-108 -3l1 77l78 2c61.3333 1.33334 91 38.3333 89 111l-10 452z" />
+ <glyph glyph-name="uniFEE0" unicode="&#x644;" horiz-adv-x="206" arabic-form="medial"
+ d="M210 901l40 -130l-40 9v-391c0 -49.3333 -4.5 -87.3333 -13.5 -114c-9 -26.6667 -21 -44.5 -36 -53.5s-36.8333 -15.8333 -65.5 -20.5l-108 -3l1 77l78 2c61.3333 1.33334 91 38.3333 89 111l-10 452z" />
+ <glyph glyph-name="uniFEE1" unicode="&#x645;" horiz-adv-x="549" arabic-form="isolated"
+ d="M280 303c-18 0 -35 -12.6667 -51 -38c-2.66667 10.6667 -4 22 -4 34c0 43.3333 26.6667 65.6667 80 67h27c18.6667 0 45.8333 -5.66666 81.5 -17s70.1667 -28.8333 103.5 -52.5c33.3333 -23.6667 50 -48.5 50 -74.5c0 -17.3333 -9.33331 -36.3333 -28 -57
+s-40 -31 -64 -31l-71 24c-46.6667 16 -86.3333 24 -119 24c-40.6667 0 -69.3333 -12 -86 -36c20 -161.333 30 -285.667 30 -373c0 -42 -7.33333 -79 -22 -111c-14.6667 87.3333 -27.3333 157.833 -38 211.5c-10.6667 53.6667 -17.8333 86.6667 -21.5 99
+c-3.66667 12.3333 -7 28.5 -10 48.5s-5.83333 52 -8.5 96v11c0 9.33333 2.5 21 7.5 35s12.8333 29.3333 23.5 46s26.5 30.8333 47.5 42.5c21 11.6667 44.8333 17.5 71.5 17.5c14 0 57 -9.33334 129 -28c-63.3333 41.3333 -106 62 -128 62z" />
+ <glyph glyph-name="uniFEE2" unicode="&#x645;" horiz-adv-x="549" arabic-form="terminal"
+ d="M280 303c-18 0 -35 -12.6667 -51 -38c-2.66667 10.6667 -4 22 -4 34c0 43.3333 26.6667 65.6667 80 67h27c18.6667 0 45.8333 -5.66666 81.5 -17s70.1667 -28.8333 103.5 -52.5c33.3333 -23.6667 50 -48.5 50 -74.5c0 -17.3333 -9.33331 -36.3333 -28 -57
+s-40 -31 -64 -31l-71 24c-46.6667 16 -86.3333 24 -119 24c-40.6667 0 -69.3333 -12 -86 -36c20 -161.333 30 -285.667 30 -373c0 -42 -7.33333 -79 -22 -111c-14.6667 87.3333 -27.3333 157.833 -38 211.5c-10.6667 53.6667 -17.8333 86.6667 -21.5 99
+c-3.66667 12.3333 -7 28.5 -10 48.5s-5.83333 52 -8.5 96v11c0 9.33333 2.5 21 7.5 35s12.8333 29.3333 23.5 46s26.5 30.8333 47.5 42.5c21 11.6667 44.8333 17.5 71.5 17.5c14 0 57 -9.33334 129 -28c-63.3333 41.3333 -106 62 -128 62z" />
+ <glyph glyph-name="uniFEE3" unicode="&#x645;" horiz-adv-x="403" arabic-form="initial"
+ d="M307 430c24.6667 0 51.1667 -20.3333 79.5 -61s42.5 -79.6667 42.5 -117c0 -40.6667 -25.6667 -65 -77 -73c-44.6667 0 -82.6667 10.6667 -114 32l-45 31c-21.3333 -26.6667 -50.6667 -40 -88 -40h-4h-101v76l101 -1c22.6667 0.666656 41.8333 6.33334 57.5 17
+s28 23.5 37 38.5s17.5 29.8333 25.5 44.5s18.6667 27.1667 32 37.5c13.3333 10.3333 29.3333 15.5 48 15.5h6zM342 240c18 0 27 11.3333 27 34c0 12.6667 -14 36.3333 -42 71l-19 14l-17 -7c-20.6667 -16.6667 -33.6667 -36 -39 -58c10 -16 23.6667 -29 41 -39
+s33.6667 -15 49 -15z" />
+ <glyph glyph-name="uniFEE4" unicode="&#x645;" horiz-adv-x="403" arabic-form="medial"
+ d="M307 430c24.6667 0 51.1667 -20.3333 79.5 -61s42.5 -79.6667 42.5 -117c0 -40.6667 -25.6667 -65 -77 -73c-44.6667 0 -82.6667 10.6667 -114 32l-45 31c-21.3333 -26.6667 -50.6667 -40 -88 -40h-4h-101v76l101 -1c22.6667 0.666656 41.8333 6.33334 57.5 17
+s28 23.5 37 38.5s17.5 29.8333 25.5 44.5s18.6667 27.1667 32 37.5c13.3333 10.3333 29.3333 15.5 48 15.5h6zM342 240c18 0 27 11.3333 27 34c0 12.6667 -14 36.3333 -42 71l-19 14l-17 -7c-20.6667 -16.6667 -33.6667 -36 -39 -58c10 -16 23.6667 -29 41 -39
+s33.6667 -15 49 -15z" />
+ <glyph glyph-name="uniFEE5" unicode="&#x646;" horiz-adv-x="651" arabic-form="isolated"
+ d="M441 451l-59 -55l-58 55l58 55zM362 -20c95.3333 0 164.833 13.5 208.5 40.5s65.5 76.5 65.5 148.5c-0.666687 104 -14.3333 166.667 -41 188l58 96c11.3333 -47.3333 18 -128.333 20 -243l-7 -78c-3.33331 -46.6667 -12 -85.6667 -26 -117
+c-14 -31.3333 -33 -54.8333 -57 -70.5c-24 -15.6667 -49.3333 -26.5 -76 -32.5c-26.6667 -6 -58.6667 -9 -96 -9c-21.3333 0 -37.6667 0.333336 -49 1c-90.6667 0 -153.5 17.6667 -188.5 53c-35 35.3333 -52.5 87.3333 -52.5 156c0 61.3333 9.33333 124.333 28 189l21 -4
+c-11.3333 -48.6667 -17 -92 -17 -130c0 -4.66667 0.333328 -11.3333 1 -20s1 -15 1 -19c0 -98 69 -147.667 207 -149z" />
+ <glyph glyph-name="uniFEE6" unicode="&#x646;" horiz-adv-x="651" arabic-form="terminal"
+ d="M441 451l-59 -55l-58 55l58 55zM362 -20c95.3333 0 164.833 13.5 208.5 40.5s65.5 76.5 65.5 148.5c-0.666687 104 -14.3333 166.667 -41 188l58 96c11.3333 -47.3333 18 -128.333 20 -243l-7 -78c-3.33331 -46.6667 -12 -85.6667 -26 -117
+c-14 -31.3333 -33 -54.8333 -57 -70.5c-24 -15.6667 -49.3333 -26.5 -76 -32.5c-26.6667 -6 -58.6667 -9 -96 -9c-21.3333 0 -37.6667 0.333336 -49 1c-90.6667 0 -153.5 17.6667 -188.5 53c-35 35.3333 -52.5 87.3333 -52.5 156c0 61.3333 9.33333 124.333 28 189l21 -4
+c-11.3333 -48.6667 -17 -92 -17 -130c0 -4.66667 0.333328 -11.3333 1 -20s1 -15 1 -19c0 -98 69 -147.667 207 -149z" />
+ <glyph glyph-name="uniFEE7" unicode="&#x646;" horiz-adv-x="323" arabic-form="initial"
+ d="M278 630l-61 -58l-62 58l62 58zM286 508c30 -40 45 -85.6667 45 -137v-68c0 -68.6667 -17.3333 -103 -52 -103h-282l-9 77h310v9c0 62.6667 -18.6667 111.667 -56 147z" />
+ <glyph glyph-name="uniFEE8" unicode="&#x646;" horiz-adv-x="323" arabic-form="medial"
+ d="M278 630l-61 -58l-62 58l62 58zM286 508c30 -40 45 -85.6667 45 -137v-68c0 -68.6667 -17.3333 -103 -52 -103h-282l-9 77h310v9c0 62.6667 -18.6667 111.667 -56 147z" />
+ <glyph glyph-name="uniFEE9" unicode="&#x647;" horiz-adv-x="424" arabic-form="isolated"
+ d="M394 315c0 -67.3333 -39 -105 -117 -113c-43.3333 0 -74.6667 3.66667 -94 11s-36 24 -50 50c-4 8 -6 19.3333 -6 34c0 26.6667 10 59.1667 30 97.5s36.6667 67.5 50 87.5l-8 10l52 72h1c40 -45.3333 66.3333 -79.3333 79 -102l51 -87c8 -20.6667 12 -40.6667 12 -60z
+M274 270c58 0 87 10.6667 87 32c0 18.6667 -10.6667 45.1667 -32 79.5s-52.6667 58.5 -94 72.5v-1c-4.66667 -4.66666 -11 -12 -19 -22l-23 -30c-7.33333 -10 -13.6667 -21.6667 -19 -35s-8 -26 -8 -38c0 -20.6667 11 -35.5 33 -44.5s47 -13.5 75 -13.5z" />
+ <glyph glyph-name="uniFEEA" unicode="&#x647;" horiz-adv-x="622" arabic-form="terminal"
+ d="M615 201c-68.6667 0 -117.833 14.1667 -147.5 42.5c-29.6667 28.3333 -52.1667 85.8333 -67.5 172.5c-21.3333 -51.3333 -57 -77 -107 -77c-108.667 2 -163 26.6667 -163 74c0 56.6667 74.3333 116.333 223 179c-2.66666 8.66669 -4 18.6667 -4 30
+c0 25.3333 8 50.6667 24 76l74 -337c29.3333 -57.3333 64.6667 -86 106 -86h94l-5 -72c-1.33331 -1.33333 -10.3333 -2 -27 -2zM199 440c0 -15.3333 11.3333 -26.5 34 -33.5s43.3333 -10.5 62 -10.5c35.3333 0 58.3333 3.66666 69 11s18.3333 22.3333 23 45
+c-2 8 -4.5 19.5 -7.5 34.5s-6 28.5 -9 40.5s-6.5 22.6667 -10.5 32c-107.333 -44.6667 -161 -84.3333 -161 -119z" />
+ <glyph glyph-name="uniFEEB" unicode="&#x647;" horiz-adv-x="525" arabic-form="initial"
+ d="M353 747c119.333 -116 179 -237.667 179 -365c0 -14 -1 -29.3333 -3 -46s-5.5 -36 -10.5 -58s-13.3333 -41.3333 -25 -58s-25.8333 -27.3333 -42.5 -32c-68 6.66667 -131.333 37.3333 -190 92c-58.6667 -52.6667 -122 -79.6667 -190 -81h-83l7 76
+c91.3333 0 165 16 221 48c-34 16 -59 52.3333 -75 109c0 111.333 71.3333 183 214 215l-56 37c4.66666 30.6667 22.6667 51.6667 54 63zM455 294c6.66666 0 14 14.3333 22 43s12 49.6667 12 63c0 62.6667 -23.3333 121.667 -70 177l-2 -47
+c-16.6667 -72.6667 -42 -130 -76 -172c63.3333 -36.6667 100.667 -58 112 -64h2zM323 423c25.3333 66 38 107.333 38 124c0 19.3333 -8 30.3333 -24 33c-32 -9.33331 -61.5 -23.5 -88.5 -42.5s-40.5 -39.8333 -40.5 -62.5c0 -26.6667 32 -55.6667 96 -87z" />
+ <glyph glyph-name="uniFEEC" unicode="&#x647;" horiz-adv-x="476" arabic-form="medial"
+ d="M378 404c0 -11.3333 -0.666656 -21 -2 -29s-5 -18.5 -11 -31.5s-17 -25.1667 -33 -36.5s-36.3333 -21 -61 -29h220v-77h-220c21.3333 -4.66667 40.6667 -15 58 -31c30.6667 -18 46 -47.3333 46 -88v-1c0 -26 -11.6667 -51.8333 -35 -77.5s-48 -38.5 -74 -38.5h-4
+c-21.3333 0 -39.1667 13.5 -53.5 40.5s-24.5 58.5 -30.5 94.5l-5 101h-191l1 77h187l9 125c10.6667 43.3333 22.8333 74.8333 36.5 94.5c13.6667 19.6667 34.1667 29.5 61.5 29.5c28 0 51.8333 -15.6667 71.5 -47s29.5 -56.6667 29.5 -76zM348 399
+c0 7.33334 -1.5 16.1667 -4.5 26.5s-9.66666 20.8333 -20 31.5s-23.5 16 -39.5 16c-19.3333 0 -34.3333 -9.83334 -45 -29.5s-17.5 -44 -20.5 -73s-7.16667 -59.8333 -12.5 -92.5h32c36.6667 15.3333 64.1667 31.5 82.5 48.5s27.5 41.1667 27.5 72.5zM209 188
+c15.3333 -104 42.3333 -157.333 81 -160c42.6667 12 64 31.6667 64 59c0 34 -14.5 61.5 -43.5 82.5s-62.8333 31.5 -101.5 31.5v-13z" />
+ <glyph glyph-name="uniFEED" unicode="&#x648;" horiz-adv-x="399" arabic-form="isolated"
+ d="M330 199h-99c-28 12 -42 42 -42 90v14c0 41.3333 14 81 42 119c16 21.3333 41 32 75 32h9c45.3333 -7.33334 73.3333 -64.6667 84 -172v-85c0 -76 -35.3333 -158.333 -106 -247c-39.3333 -50 -95 -75 -167 -75h-53v10c79.3333 46 129.167 78 149.5 96
+s45.5 51.6667 75.5 101c22.6667 36.6667 34 69 34 97c0 4 -0.666656 10.6667 -2 20zM341 288c-1.33334 35.3333 -4.66666 61.1667 -10 77.5s-16 24.5 -32 24.5c-30 0 -45 -34 -45 -102h10c5.33334 0 14.1667 -0.166656 26.5 -0.5s21.5 -0.5 27.5 -0.5
+c10.6667 0 18.3333 0.333344 23 1z" />
+ <glyph glyph-name="uniFEEE" unicode="&#x648;" horiz-adv-x="399" arabic-form="terminal"
+ d="M330 199h-99c-28 12 -42 42 -42 90v14c0 41.3333 14 81 42 119c16 21.3333 41 32 75 32h9c45.3333 -7.33334 73.3333 -64.6667 84 -172v-85c0 -76 -35.3333 -158.333 -106 -247c-39.3333 -50 -95 -75 -167 -75h-53v10c79.3333 46 129.167 78 149.5 96
+s45.5 51.6667 75.5 101c22.6667 36.6667 34 69 34 97c0 4 -0.666656 10.6667 -2 20zM341 288c-1.33334 35.3333 -4.66666 61.1667 -10 77.5s-16 24.5 -32 24.5c-30 0 -45 -34 -45 -102h10c5.33334 0 14.1667 -0.166656 26.5 -0.5s21.5 -0.5 27.5 -0.5
+c10.6667 0 18.3333 0.333344 23 1z" />
+ </font>
+ <path d="M20,10 L20,280" stroke="#BBB" />
+ <path d="M240,10 L240,280" stroke="#BBB" />
+ <path d="M460,10 L460,280" stroke="#BBB" />
+ <path d="M10,60 L470,60" stroke="#BBB" />
+ <path d="M10,150 L470,150" stroke="#BBB" />
+ <path d="M10,240 L470,240" stroke="#BBB" />
+ <g font-family="Andalus,Diwani Letter,serif" font-size="50">
+ <text text-anchor="middle" x="240" y="60" xml:lang="ar" fill="#700">آلات</text>
+ <text text-anchor="start" x="460" y="60" xml:lang="ar">آلات</text>
+ <text text-anchor="end" x="20" y="60" xml:lang="ar" fill="#009">آلات</text>
+ </g>
+ <g font-family="FreeSerif, svgSerifHebrewArabic,serif" font-size="50">
+ <text text-anchor="middle" x="240" y="150" xml:lang="ar" fill="#700">مص</text>
+ <text text-anchor="start" x="460" y="150" xml:lang="ar">مص</text>
+ <text text-anchor="end" x="20" y="150" xml:lang="ar" fill="#009">مص</text>
+ <!--
+ <text text-anchor="middle" x="380" y="320">&#x627;&#xfee0;&#xfee0;&#xfeea; &#x0644;&#x0627;</text>
+ -->
+ </g>
+ <g font-family="svgSerifHebrewArabic,serif" font-size="50">
+ <text text-anchor="middle" x="240" y="240" xml:lang="he" fill="#700">פעילות </text>
+ <text text-anchor="start" x="460" y="240" xml:lang="he">פעילות</text>
+ <text text-anchor="end" x="20" y="240" xml:lang="he" fill="#009">פעילות</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.10 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
+
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-201-t.svg
new file mode 100644
index 0000000000..cce3527060
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-201-t.svg
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ASL" owner="AE" desc="Testing 'textArea' with fixed 'width' and 'height'" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: text-area-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Testing 'textArea' with fixed 'width' and 'height'</p>
+ <p>
+ Lines should break at character boundaries if there is not enough room to perform word breaks.
+ The 'height' of the first 'textArea' below (top-right) is less than that of the characters
+ so nothing should appear.
+ </p>
+ <p>The text is taken from "The Lost Princess of Oz" by Baum, L. Frank (Lyman Frank), 1856-1919</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-area-201-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g text-anchor="middle" font-size="10" fill="#555">
+ <text xml:id="display-title" x="240" y="30" font-size="14" fill="#000">TextArea with Fixed Width and Height</text>
+ <text xml:id="comment-1" x="240" y="45">
+ Lines should break at character boundaries if there is not enough room to perform word breaks.
+ </text>
+ <text xml:id="comment-2" x="240" y="57">
+ The 'height' of the first 'textArea' below (top-right) is less than that of the characters
+ </text>
+ <text xml:id="comment-3" x="240" y="69">
+ so nothing should appear.
+ </text>
+ </g>
+ <text x="465" y="295" font-size="8" text-anchor="end" fill="#555">
+ Excerpt from "The Lost Princess of Oz" by Baum, L. Frank (Lyman Frank), 1856-1919
+ </text>
+ <rect x="15" y="80" width="48" height="200" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="15" y="80" width="48" height="200" font-size="24" fill="#369">Together they searched all through the great palace and even to the farthest limits of the palace grounds, which were quite extensive, but nowhere could they find a trace of Ozma. When Dorothy returned to where Betsy and Trot awaited her, the little girl's face was rather solemn and troubled, for never before had Ozma gone away without telling her friends where she was going, or without an escort that befitted her royal state.</textArea>
+ <rect x="75" y="80" width="390" height="15" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="75" y="80" width="390" height="15" font-size="24" fill="#396">Together they searched all through the great palace and even to the farthest limits of the palace grounds, which were quite extensive, but nowhere could they find a trace of Ozma. When Dorothy returned to where Betsy and Trot awaited her, the little girl's face was rather solemn and troubled, for never before had Ozma gone away without telling her friends where she was going, or without an escort that befitted her royal state.</textArea>
+ <rect x="75" y="105" width="390" height="175" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="75" y="105" width="390" height="175" font-size="24" fill="#396">Together they searched all through the great palace and even to the farthest limits of the palace grounds, which were quite extensive, but nowhere could they find a trace of Ozma. When Dorothy returned to where Betsy and Trot awaited her, the little girl's face was rather solemn and troubled, for never before had Ozma gone away without telling her friends where she was going, or without an escort that befitted her royal state.</textArea>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-202-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-202-t.svg
new file mode 100644
index 0000000000..f30ade1bd8
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-202-t.svg
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ASL" owner="AE" desc="Testing 'textArea' with fixed 'width' and 'height'" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: text-area-202-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Testing 'textArea' with fixed 'width' and 'height'</p>
+ <p>
+ Three 'textArea' elements contain words which are increasing in 'font-size'.
+
+ To pass, no characters should appear in the top-right box since the 'height' of the 'textArea' is less
+ than that of the characters.
+
+ There should be no characters outside of the border of the larger bottom-left box.
+
+ In the left-side box, there may be characters outside of the border, depending on whether
+ the implementation breaks words or not.
+ </p>
+ <p>The text is taken from "The Lost Princess of Oz" by Baum, L. Frank (Lyman Frank), 1856-1919</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-area-202-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g text-anchor="middle" font-size="10" fill="#555">
+ <text xml:id="display-title" x="240" y="30" font-size="14" fill="#000">TextArea with Fixed Width and Height</text>
+ </g>
+ <text x="465" y="295" font-size="8" text-anchor="end" fill="#555">
+ Excerpt from "The Lost Princess of Oz" by Baum, L. Frank (Lyman Frank), 1856-1919
+ </text>
+ <rect x="15" y="80" width="48" height="200" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="15" y="80" width="48" height="200" font-size="10" fill="#936">
+ <tspan>
+ <tspan font-size="10">Together </tspan>
+ <tspan font-size="11">they </tspan>
+ <tspan font-size="12">searched </tspan>
+ <tspan font-size="13">all </tspan>
+ <tspan font-size="14">through </tspan>
+ <tspan font-size="15">the </tspan>
+ <tspan font-size="16">great </tspan>
+ <tspan font-size="17">palace </tspan>
+ <tspan font-size="18">and </tspan>
+ <tspan font-size="19">even </tspan>
+ <tspan font-size="20">to </tspan>
+ <tspan font-size="21">the </tspan>
+ <tspan font-size="22">farthest </tspan>
+ <tspan font-size="23">limits </tspan>
+ <tspan font-size="24">of </tspan>
+ <tspan font-size="25">the </tspan>
+ <tspan font-size="26">palace </tspan>
+ <tspan font-size="27">grounds, </tspan>
+ <tspan font-size="28">which </tspan>
+ <tspan font-size="29">were </tspan>
+ <tspan font-size="30">quite </tspan>
+ <tspan font-size="31">extensive </tspan>
+ </tspan>
+ </textArea>
+ <rect x="75" y="80" width="390" height="15" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="75" y="80" width="390" height="15" font-size="10" fill="#396">
+ <tspan>
+ <tspan font-size="10">Together </tspan>
+ <tspan font-size="11">they </tspan>
+ <tspan font-size="12">searched </tspan>
+ <tspan font-size="13">all </tspan>
+ <tspan font-size="14">through </tspan>
+ <tspan font-size="15">the </tspan>
+ <tspan font-size="16">great </tspan>
+ <tspan font-size="17">palace </tspan>
+ <tspan font-size="18">and </tspan>
+ <tspan font-size="19">even </tspan>
+ <tspan font-size="20">to </tspan>
+ <tspan font-size="21">the </tspan>
+ <tspan font-size="22">farthest </tspan>
+ <tspan font-size="23">limits </tspan>
+ <tspan font-size="24">of </tspan>
+ <tspan font-size="25">the </tspan>
+ <tspan font-size="26">palace </tspan>
+ <tspan font-size="27">grounds, </tspan>
+ <tspan font-size="28">which </tspan>
+ <tspan font-size="29">were </tspan>
+ <tspan font-size="30">quite </tspan>
+ <tspan font-size="31">extensive </tspan>
+ </tspan>
+ </textArea>
+ <rect x="75" y="105" width="390" height="175" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="75" y="105" width="390" height="175" font-size="10" fill="#396">
+ <tspan>
+ <tspan font-size="10">Together </tspan>
+ <tspan font-size="11">they </tspan>
+ <tspan font-size="12">searched </tspan>
+ <tspan font-size="13">all </tspan>
+ <tspan font-size="14">through </tspan>
+ <tspan font-size="15">the </tspan>
+ <tspan font-size="16">great </tspan>
+ <tspan font-size="17">palace </tspan>
+ <tspan font-size="18">and </tspan>
+ <tspan font-size="19">even </tspan>
+ <tspan font-size="20">to </tspan>
+ <tspan font-size="21">the </tspan>
+ <tspan font-size="22">farthest </tspan>
+ <tspan font-size="23">limits </tspan>
+ <tspan font-size="24">of </tspan>
+ <tspan font-size="25">the </tspan>
+ <tspan font-size="26">palace </tspan>
+ <tspan font-size="27">grounds, </tspan>
+ <tspan font-size="28">which </tspan>
+ <tspan font-size="29">were </tspan>
+ <tspan font-size="30">quite </tspan>
+ <tspan font-size="31">extensive </tspan>
+ <tspan font-size="32">but </tspan>
+ <tspan font-size="33">nowhere </tspan>
+ <tspan font-size="34">could </tspan>
+ <tspan font-size="36">they </tspan>
+ <tspan font-size="37">find </tspan>
+ <tspan font-size="38">a </tspan>
+ <tspan font-size="39">trace </tspan>
+ <tspan font-size="40">of </tspan>
+ <tspan font-size="41">Ozma. </tspan>
+ </tspan>
+ </textArea>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!-- <g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>
+ -->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-205-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-205-t.svg
new file mode 100644
index 0000000000..c72cf5091c
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-205-t.svg
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ASL" owner="AE" desc="TextArea with Height Set to Auto" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: text-area-205-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>TextArea with Height Set to Auto</p>
+ <p>Text should wrap at the right-hand margin and continue to the end of the paragraph.</p>
+ <p>The text is taken from "The Lost Princess of Oz" by Baum, L. Frank (Lyman Frank), 1856-1919</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-area-205-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text xml:id="display-title" x="240" y="30" font-size="14" text-anchor="middle" fill="#000">TextArea with Height Set to Auto</text>
+ <text xml:id="comment-1" x="240" y="45" font-size="11" text-anchor="middle" fill="#555">Text should wrap at the right-hand margin and continue to the end of the paragraph.</text>
+ <text x="465" y="290" font-size="8" text-anchor="end" fill="#555">Excerpt from "The Lost Princess of Oz" by Baum, L. Frank (Lyman Frank), 1856-1919</text>
+ <line x1="15" y1="60" x2="465" y2="60" stroke="black" stroke-width="0.25"/>
+ <line x1="15" y1="60" x2="15" y2="275" stroke="black" stroke-width="0.25"/>
+ <line x1="465" y1="60" x2="465" y2="275" stroke="black" stroke-width="0.25"/>
+ <textArea x="15" y="60" width="450" height="auto" font-size="16" fill="#259" text-align="start">
+ With this, he jumped upon the back of the Sawhorse again, and the quaint steed, which never tired, dashed away at full speed. The three girls were very much disturbed in mind. Even the Patchwork Girl seemed to realize that a great calamity had overtaken them all. Ozma was a fairy of considerable power, and all the creatures in Oz as well as the three mortal girls from the outside world looked upon her as their protector and friend. The idea of their beautiful girl Ruler's being overpowered by an enemy and dragged from her splendid palace a captive was too astonishing for them to comprehend at first. Yet what other explanation of the mystery could there be?
+ </textArea>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-206-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-206-t.svg
new file mode 100644
index 0000000000..79c60d133f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-206-t.svg
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ASL" owner="AE" desc="TextArea with Line-increment and Tbreak" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: text-area-206-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>TextArea with Line-increment and Tbreak</p>
+ <p>The blue lines should appear below each of the five text lines in the 'textArea'.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-area-206-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text xml:id="display-title" x="240" y="30" font-size="14" text-anchor="middle" fill="#000">TextArea with Line-increment and Tbreak</text>
+ <text xml:id="comment-1" x="240" y="45" font-size="11" text-anchor="middle" fill="#555">
+ The blue lines should appear below each of the five text lines in the 'textArea'.
+ </text>
+ <g stroke="blue" stroke-width="1.5" stroke-opacity="0.6">
+ <line x1="15" y1="75" x2="465" y2="75"/>
+ <line x1="15" y1="95" x2="465" y2="95"/>
+ <line x1="15" y1="125" x2="465" y2="125"/>
+ <line x1="15" y1="175" x2="465" y2="175"/>
+ <line x1="15" y1="275" x2="465" y2="275"/>
+ </g>
+ <rect x="15" y="60" width="450" height="225" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="15" y="60" width="450" height="225" fill="#285" text-align="start">
+ <tspan line-increment="15">
+ 1. 'line-increment' set to 15.<tspan font-size="15">ABCDEF</tspan>
+ </tspan>
+ <tspan line-increment="20">
+ <tbreak/>2. 'line-increment' set to 20. <tspan font-size="20">ABCDEF</tspan>
+ </tspan>
+ <tspan line-increment="30">
+ <tbreak/>3. 'line-increment' set to 30. <tspan font-size="30">ABCDEF</tspan>
+ </tspan>
+ <tspan line-increment="50">
+ <tbreak/>4. 'line-increment' set to 50. <tspan font-size="50">ABCDEF</tspan>
+ </tspan>
+ <tspan line-increment="100">
+ <tbreak/>5. 'line-increment' set to 100. <tspan font-size="100">ABCD</tspan>
+ </tspan>
+ </textArea>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-207-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-207-t.svg
new file mode 100644
index 0000000000..05922f9813
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-207-t.svg
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ASL" owner="AE" desc="TextArea Transformed by Rotation" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: text-area-207-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>TextArea Transformed by Rotation</p>
+ <p>The three 'textArea's should be rotated by 35, 90 and 180 degrees.</p>
+ <p>The text is taken from "The Lost Princess of Oz" by Baum, L. Frank (Lyman Frank), 1856-1919</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-area-207-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text xml:id="display-title" x="240" y="30" font-size="14" text-anchor="middle" fill="#000">TextArea Transformed by Rotation</text>
+ <text xml:id="comment-1" x="240" y="45" font-size="11" text-anchor="middle" fill="#555">
+ The three textArea's should be rotated by 35, 90 and 180 degrees.
+ </text>
+ <text x="465" y="290" font-size="8" text-anchor="end" fill="#555" visibility="visible">
+ Excerpts from "The Lost Princess of Oz" by Baum, L. Frank (Lyman Frank), 1856-1919
+ </text>
+ <g transform="rotate(35,80,-15)">
+ <rect x="130" y="40" width="195" height="130" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="130" y="40" width="195" height="130" font-size="14" fill="#259">
+ "Stone, is it?" Scraps, who was again dancing wildly around, for she never tired and could never keep still for long.<tbreak/>
+ "Course it's stone," answered Betsy scornfully.<tbreak/>
+ "Can't you see?"<tbreak/>
+ "Yes," said Scraps, going closer. "I can SEE the wall, but I can't FEEL it." And then, with her arms outstretched, she did a very queer thing. She walked right into the wall and disappeared.<tbreak/>
+ "For goodness sake!" Dorothy, amazed, as indeed they all were.<tbreak/>
+ "The gates must be around the other side," said the Wizard. "Let us follow the curve of the wall until we reach an opening in it."<tbreak/>
+ "Which way?" asked Dorothy.<tbreak/>
+ "We must guess that," he replied. "Suppose we go to the left. One direction is as good as another." They formed in marching order and went around the city wall to the left. It wasn't a big city, as I have said, but to go way around it outside the high wall was quite a walk, as they became aware. But around it our adventurers went without finding any sign of a gateway or other opening. When they had returned to the little mound from which they had started, they dismounted from the animals and again seated themselves on the grassy mound.
+ </textArea>
+ </g>
+ <g transform="rotate(90,50,50)">
+ <rect x="65" y="-365" width="100" height="205" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="65" y="-365" width="100" height="205" font-size="14" fill="#259">
+ The others of the party, however they might be puzzled by the serious problem that confronted them, would not allow themselves to despair.<tbreak/>
+ "If we once get over these mountains," said Button-Bright, "we could probably get along all right."<tbreak/>
+ "True enough," agreed Dorothy. "So we must find some way, of course, to get past these whirligig hills. But how?"<tbreak/>
+ "I wish the Ork was with us," sighed Trot.<tbreak/>
+ "But the Ork isn't here," said the Wizard, "and we must depend upon ourselves to conquer this difficulty. Unfortunately, all my magic has been stolen, otherwise I am sure could easily get over the mountains."<tbreak/>
+ "Unfortunately," observed the Woozy, "none of us has wings. And we're in a magic country without any magic."<tbreak/>
+ "What is that around your waist, Dorothy?" asked the Wizard.<tbreak/>
+ "That? Oh, that's just the Magic Belt I once captured from the Nome King," she replied.
+ </textArea>
+ </g>
+ <g transform="rotate(180,50,50)">
+ <rect x="-365" y="-175" width="205" height="100" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="-365" y="-175" width="205" height="100" font-size="14" fill="#259">
+ "A Magic Belt! Why, that's fine. I'm sure a Magic Belt would take you over these hills.".<tbreak/>
+ "It might if I knew how to work it," said the little girl. "Ozma knows a lot of its magic, but I've never found out about it. All I know is that while I am wearing it, nothing can hurt me.".<tbreak/>
+ "Try wishing yourself across and see if it will obey you," suggested the Wizard..<tbreak/>
+ "But what good would that do?" asked Dorothy. "If I got across, it wouldn't help the rest of you, and I couldn't go alone among all those giants and dragons while you stayed here.".<tbreak/>
+ "True enough," agreed the Wizard sadly. And then, after looking around the group, he inquired, "What is that on your finger, Trot?".<tbreak/>
+ "A ring. The Mermaids gave it to me," she explained, "and if ever I'm in trouble when I'm on the water, I can call the Mermaids and they'll come and help me. But the Mermaids can't help me on the land, you know, 'cause they swim, and--and--they haven't any legs.".<tbreak/>
+ "True enough," repeated the Wizard, more sadly.
+ </textArea>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-208-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-208-t.svg
new file mode 100644
index 0000000000..4329580987
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-208-t.svg
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ASL" owner="AE" desc="TextArea with Both Width and Height Set to Auto" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: text-area-208-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>TextArea with Both Width and Height Set to Auto</p>
+ <p>
+ The eight lines of numbers should not wrap. Each line is terminated by a tbreak element.
+ They have numbers from 0 to 50. Each line increases the 'font-size' by 25%.
+ The 'line-increment' attribute is not used.
+ </p>
+ <p>
+ This test is passed if eight lines of numbers are rendered and not
+ wrapped to a new line. Numbers displayed will decrease with each line.
+ Every line must begin with number 0.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-area-208-t.svg,v $</title>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text xml:id="display-title" x="240" y="25" font-size="14" text-anchor="middle" fill="#000">TextArea with Both Width and Height Set to Auto</text>
+ <text xml:id="comment-1" x="240" y="40" font-size="11" text-anchor="middle" fill="#555">
+ The following eight lines of numbers should not wrap. They have numbers from 0 to 50.
+ </text>
+ <text xml:id="comment-2" x="240" y="52" font-size="11" text-anchor="middle" fill="#555">
+ Each line increases the 'font-size' by 25%. The 'line-increment' attribute is not used.
+ </text>
+ <line x1="15" y1="63" x2="465" y2="63" stroke="black" stroke-width="0.25"/>
+ <line x1="15" y1="63" x2="15" y2="290" stroke="black" stroke-width="0.25"/>
+ <textArea x="15" y="60" width="auto" height="auto" font-size="13" xml:space="default">
+ <tspan fill="#285">
+ <tspan font-size="13">0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50</tspan>
+ <tspan font-size="16.25">
+ <tbreak/>0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
+ </tspan>
+ <tspan font-size="19.5">
+ <tbreak/>0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
+ </tspan>
+ <tspan font-size="22.75">
+ <tbreak/>0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
+ </tspan>
+ <tspan font-size="26">
+ <tbreak/>0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
+ </tspan>
+ <tspan font-size="29.25">
+ <tbreak/>0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
+ </tspan>
+ <tspan font-size="32.5">
+ <tbreak/>0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
+ </tspan>
+ <tspan font-size="35.75">
+ <tbreak/>0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
+ </tspan>
+ </tspan>
+ </textArea>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-209-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-209-t.svg
new file mode 100644
index 0000000000..8406f602d7
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-209-t.svg
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ASL" owner="AE" desc="TextArea Testing Word Breaks and Tbreak" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: text-area-209-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>TextArea Testing Word Breaks and Tbreak</p>
+ <p>
+ Each word should break onto a new line. The left-hand 'textArea' has no 'tbreak' elements
+ while the right-hand one uses 'tbreak' after each word. Both should appear the same.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-area-209-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text xml:id="display-title" x="240" y="25" font-size="14" text-anchor="middle" fill="#000">TextArea Testing Word Breaks and Tbreak</text>
+ <text xml:id="comment-1" x="240" y="40" font-size="11" text-anchor="middle" fill="#555">
+ Each word should break onto a new line. The left-hand 'textArea' has no 'tbreak' elements
+ </text>
+ <text xml:id="comment-2" x="240" y="52" font-size="11" text-anchor="middle" fill="#555">
+ while the right-hand one uses 'tbreak' after each word. Both should appear the same.
+ </text>
+ <rect x="15" y="65" height="220" width="220" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="15" y="65" height="220" width="220" font-size="12" xml:space="default" fill="#359">
+ Pseudopseudohypoparathyroidism Dichlorodiphenyltrichloroethane Floccinaucinihilipilification Honorificabilitudinitatibus Trinitrophenylmethylnitramine Paradimethylaminobenzaldehyde Cystoureteropyelonephritis Ethylenediaminetetraacetate Octamethylpyrophosphoramide Electroencephalographically Antitransubstantiationalist Hydroxydesoxycorticosterone Methylchloroisothiazolinone Ethylenediaminetetraacetic Anhydrohydroxyprogesterone Antidisestablishmentarianism Requeterequeteacostumbrado Superpsicoanalisticamente Anticonstitutionnellement Sobreabundantisimamente Apesadumbradisimamente Otorrinolaringologistico Endocrinologicamente
+ </textArea>
+ <rect x="245" y="65" height="220" width="220" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="245" y="65" height="220" width="220" font-size="12" xml:space="default" fill="#359">
+ Pseudopseudohypoparathyroidism <tbreak/>Dichlorodiphenyltrichloroethane <tbreak/>Floccinaucinihilipilification <tbreak/>Honorificabilitudinitatibus <tbreak/>Trinitrophenylmethylnitramine <tbreak/>Paradimethylaminobenzaldehyde <tbreak/>Cystoureteropyelonephritis <tbreak/>Ethylenediaminetetraacetate <tbreak/>Octamethylpyrophosphoramide <tbreak/>Electroencephalographically <tbreak/>Antitransubstantiationalist <tbreak/>Hydroxydesoxycorticosterone <tbreak/>Methylchloroisothiazolinone <tbreak/>Ethylenediaminetetraacetic <tbreak/>Anhydrohydroxyprogesterone <tbreak/>Antidisestablishmentarianism <tbreak/>Requeterequeteacostumbrado <tbreak/>Superpsicoanalisticamente <tbreak/>Anticonstitutionnellement <tbreak/>Sobreabundantisimamente <tbreak/>Apesadumbradisimamente <tbreak/>Otorrinolaringologistico <tbreak/>Endocrinologicamente <tbreak/>
+ </textArea>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-210-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-210-t.svg
new file mode 100644
index 0000000000..b631dc35d6
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-210-t.svg
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ASL" owner="AE" desc="Testing 'rotate' attribute" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: text-area-210-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Testing "tbreak"</p>
+ <p>The gap between the lines should be as described</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-area-210-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text xml:id="display-title" x="240" y="30" font-size="14" text-anchor="middle" fill="#000">&lt;tbreak&gt;</text>
+ <text xml:id="comment-1" x="240" y="45" font-size="11" text-anchor="middle" fill="#555">This slides tests the behaviour of &lt;tbreak&gt; in various situations</text>
+
+ <rect x="15" y="60" height="215" width="450" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="15" y="60" width="450" height="215" font-size="16" fill="#259"><tbreak/>
+This line should not be at the top of the textArea<tbreak/>
+This line should be immediately below the previous one<tbreak/>
+<tbreak/>
+There should be a gap between this line and the previous<tbreak/>
+<tbreak/>
+ <tbreak/>
+There should be a big gap between this line and the previous<tbreak/>
+<tspan line-increment="32"><tbreak/></tspan>
+There should be a big gap between this line and the previous<tbreak/>
+<tbreak/>
+<tbreak/>
+<tbreak/>
+<tbreak/>
+<tbreak/>
+<tbreak/>
+<tbreak/>
+<tbreak/>
+<tspan fill="red">This line should not be visible !</tspan>
+ </textArea>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-221-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-221-t.svg
new file mode 100644
index 0000000000..1a1fad5889
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-221-t.svg
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ASL" owner="AE" desc="TextArea with Line-increment and Text-anchor" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: text-area-221-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>TextArea with line-increment, text-align and display-align</p>
+ <p>
+ All text should be centered vertically and horizontally.
+ The 'font-size' is varied along with 'line-increment'.
+ </p>
+ <p>The text is taken from "The Lost Princess of Oz" by Baum, L. Frank (Lyman Frank), 1856-1919</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-area-221-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text xml:id="display-title" x="240" y="25" font-size="14" text-anchor="middle" fill="#000">TextArea with line-increment, text-align and display-align</text>
+ <text xml:id="comment-1" x="240" y="40" font-size="11" text-anchor="middle" fill="#555">
+ All text should be centered horizontally and vertically.
+ </text>
+ <text x="465" y="290" font-size="8" text-anchor="end" fill="#555" visibility="hidden">
+ Excerpt from "The Lost Princess of Oz" by Baum, L. Frank (Lyman Frank), 1856-1919
+ </text>
+ <rect x="15" y="60" width="450" height="220" fill="none" stroke="black" stroke-width="0.25"/>
+ <textArea x="15" y="60" width="450" height="220" fill="#259" text-align="center" font-size="40" display-align="center">
+ The Lost Princess of Oz
+ <tspan line-increment="25">
+ <tbreak/>
+ </tspan>
+ <tspan font-size="20">
+ by<tbreak/>
+ </tspan>
+ <tspan font-size="24" line-increment="28">
+ Baum, L. Frank (Lyman Frank)<tbreak/>
+ <tspan font-size="18">1856-1919</tspan>
+ <tbreak/>
+ </tspan>
+ <tspan font-size="16" line-increment="20">
+ The eleventh book in the OZ set<tbreak/>
+ Published 1917
+ </tspan>
+ </textArea>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-222-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-222-t.svg
new file mode 100644
index 0000000000..b2b71bc0bf
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-area-222-t.svg
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ASL" owner="AE" desc="Testing 'textArea' with fixed 'width' and 'height'" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: text-area-222-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Testing 'textArea' with editable attribute</p>
+ <p>Activating a textArea element should bring up UI asking for new text</p>
+ <p>The initial text is taken from "The Lost Princess of Oz" by Baum, L. Frank (Lyman Frank), 1856-1919</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-area-222-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g text-anchor="middle" font-size="10" fill="#555">
+ <text xml:id="display-title" x="240" y="30" font-size="14" fill="#000">TextArea with editable attribute</text>
+ <text xml:id="comment-1" x="240" y="45">
+ Activating a textArea element should allow edit of textArea contents.
+ </text>
+ </g>
+ <text x="465" y="295" font-size="8" text-anchor="end" fill="#555">
+ Excerpt from "The Lost Princess of Oz" by Baum, L. Frank (Lyman Frank), 1856-1919
+ </text>
+ <rect x="15" y="80" width="48" height="200" fill="none" stroke="black" stroke-width="2">
+ <set attributeName="stroke" to="red" begin="text1.focusin" end="text1.focusout"/>
+ </rect>
+
+ <textArea xml:id="text1" editable="simple" x="15" y="80" width="48" height="200" font-size="24" fill="#369">Together they searched all through the great palace and even to the farthest limits of the palace grounds, which were quite extensive, but nowhere could they find a trace of Ozma.</textArea>
+
+ <rect x="75" y="105" width="390" height="175" fill="none" stroke="black" stroke-width="2">
+ <set attributeName="stroke" to="red" begin="text2.focusin" end="text2.focusout"/>
+ </rect>
+
+ <textArea xml:id="text2" editable="simple" x="75" y="105" width="390" height="175" font-size="24" fill="#396">Together they searched all through the great palace and even to the farthest limits of the palace grounds, which were quite extensive, but nowhere could they find a trace of Ozma.</textArea>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-edit-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-edit-201-t.svg
new file mode 100644
index 0000000000..9e5eca0b89
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-edit-201-t.svg
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE,AN" owner="ED" desc="Test editable in textArea" status="accepted"
+ approved="yes"
+ version="$Revision: 1.5 $" testname="$RCSfile: text-edit-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test checks basic text-editing capabilities.
+ </p>
+ <p>
+ Start editing by activating the textArea that has a green dashed outline.
+ This textArea has no child text content, but has a defined width and height.
+ Input the string "123 456" (one two three, space, space, four five six).
+
+ After input is complete, click the button labeled "Check #1". If the frame around
+ the textArea goes from being dashed to being solid then that part of the test has passed.
+ Another condition is that the text string "123 456" should look like it only has one space
+ and not two due to the whitespace handling rules.
+ </p>
+ <p>
+ Next activate the middle textArea that has a red dashed outline.
+ Input two spaces between 3 and 4. Now since this textArea has xml:space="preserve" those
+ two spaces should be rendered as two spaces, meaning it must look different from the first
+ textArea on the left. The textContent must be the same in both cases though, and this is
+ verified by clicking the button labeled "Check #2". If the test is successful the frame
+ will turn from dashed red to solid red.
+ </p>
+ <p>
+ Finally activate the rightmost textArea that has a blue dashed outline.
+ Then exit the editing mode without changing the text. The text must not change and the 'tbreak' element
+ must be kept in the position it's in. Now activate the textArea again and input an additional linebreak between 3 and 4.
+ The line "345" must now be on the third line, the second line being blank.
+ Click the button labeled "Check #3" to verify the result, the frame will turn from dashed
+ blue to solid blue if successful.
+ </p>
+ <p>
+ The test has passed if after inputting text according to the instructions above and clicking the three
+ buttons the rendered image matches the reference image exactly.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-edit-201-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18" stroke-width="2">
+
+ <text y="50" x="240" text-anchor="middle">Test editable text in textArea</text>
+
+ <g transform="translate(50,100)">
+ <text x="50" y="-10" text-anchor="middle" font-size="9" xml:space="preserve">Input the string "123 456" (two spaces).</text>
+
+ <textArea xml:id="ta1" width="100" height="100" pointer-events="boundingBox" editable="simple"> </textArea>
+ <rect xml:id="r1" width="100" height="100" stroke="green" fill="none" stroke-dasharray="5,5"/>
+
+ <rect y="110" width="100" height="20" rx="5" fill="none" stroke="green" pointer-events="fill">
+ <handler xe:event="click">
+ if(document.getElementById("ta1").textContent == "123 456")
+ document.getElementById("r1").setAttributeNS(null, "stroke-dasharray", "none");
+ </handler>
+ </rect>
+ <text x="50" y="126" text-anchor="middle" pointer-events="none">Check #1</text>
+ </g>
+ <g transform="translate(190,140)">
+ <text x="50" y="-10" text-anchor="middle" font-size="9">Insert two spaces between 3 and 4.</text>
+
+ <textArea xml:id="ta2" width="100" height="100" xml:space="preserve" pointer-events="boundingBox" editable="simple">123456</textArea>
+ <rect xml:id="r2" width="100" height="100" stroke="red" fill="none" stroke-dasharray="5,5"/>
+
+ <rect y="110" width="100" height="20" rx="5" fill="none" stroke="red" pointer-events="fill">
+ <handler xe:event="click">
+ if(document.getElementById("ta2").textContent == "123 456")
+ document.getElementById("r2").setAttributeNS(null, "stroke-dasharray", "none");
+ </handler>
+ </rect>
+ <text x="50" y="126" text-anchor="middle" pointer-events="none">Check #2</text>
+ </g>
+ <g transform="translate(330,100)">
+ <text x="50" y="-10" text-anchor="middle" font-size="9">Insert an additional linefeed between 3 and 4.</text>
+
+ <textArea xml:id="ta3" width="100" height="100" pointer-events="boundingBox" editable="simple">
+ 123<tbreak/>456
+ </textArea>
+ <rect xml:id="r3" width="100" height="100" stroke="blue" fill="none" stroke-dasharray="5,5"/>
+
+ <rect y="110" width="100" height="20" rx="5" fill="none" stroke="blue" pointer-events="fill">
+ <handler xe:event="click">
+ <![CDATA[
+ var ta = document.getElementById("ta3");
+ if (ta.textContent == "123456" &&
+ ta.firstElementChild.localName == 'tbreak' &&
+ ta.lastElementChild.localName == 'tbreak' &&
+ ta.firstElementChild != ta.lastElementChild &&
+ ta.firstElementChild.nextElementSibling == ta.lastElementChild)
+ document.getElementById("r3").setAttributeNS(null, "stroke-dasharray", "none");
+ ]]>
+ </handler>
+ </rect>
+ <text x="50" y="126" text-anchor="middle" pointer-events="none">Check #3</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.5 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!-- <g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>
+ -->
+</svg> \ No newline at end of file
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-01-t.svg
new file mode 100644
index 0000000000..736853ad15
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-01-t.svg
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="DS" owner="CL," desc="Test that viewer has the basic capability to handle different font families" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: text-fonts-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Purpose of test is to determine if the font family is being correctly selected. The top two lines of text test serif fonts; the top line in maroon tests the generic font family 'serif' and the second line in black tests a selection of commonly available named serif fonts. The next two lines of text test sans-serif fonts; the top line in maroon tests the generic font family 'sans-serif' and the second line in black tests a selection of commonly available named sans serif fonts. The following two lines of text test monospaced fonts; the top line in maroon tests the generic font family 'monospaced' and the second line in black tests a selection of commonly available named monospaced fonts. The lowercase 'i' and uppercase'W' should be the same width,for monospaced fonts.</p>
+ <p>The seventh line of text, in green, tests for three non-existent fonts (nonsense names). There is no fallback generic font specified. The text must be displayed anyway.</p>
+ <p>The first six lines contain two Japanese characters (&#x753B;&#x50CF;) at the end of the line. Both of these characters must be displayed, although it is compliant to display them with the 'missing glyph' if no suitable font containing Japanese characters can be found. Most but not all fonts have a visible missing glyph character. If the selected font has a visible missing glyph character, it should appear wherever the corresponding glyph is not available.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-fonts-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g font-weight="normal" font-size="24" stroke="none">
+ <text font-family="Georgia, 'Minion Web', 'Times New Roman', Times, 'MS PMincho', Heisei-Mincho, serif " x="20" y="80">A serifed face 画像</text>
+ <text font-family="Arial, 'Arial Unicode', 'Myriad Web', Geneva, 'Lucida Sans Unicode', 'MS PGothic', Osaka, sans-serif " x="20" y="160">A sans-serif face 画像</text>
+ <text font-family="'Lucida Console', 'Courier New', Courier, Monaco, 'MS Gothic', Osaka-Mono, monospace" x="20" y="240">A mono (iW) face 画像</text>
+ <g xml:id="generic" fill="maroon">
+ <text font-family="serif" x="40" y="50">A serifed face 画像</text>
+ <text font-family="sans-serif " x="40" y="130">A sans-serif face 画像</text>
+ <text font-family="monospace " x="40" y="210">A mono (iW) face 画像</text>
+ </g>
+ <text fill="green" font-family="'No such font at all', 'another fictitious one', sillynamewithoutspaces" x="40" y="290">This must be displayed</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-02-t.svg
new file mode 100644
index 0000000000..4195f0c1f8
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-02-t.svg
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="DS" owner="CL," desc="Test that viewer has the basic capability to handle different font weights" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: text-fonts-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Purpose of test is to determine if the font weight is being correctly rendered. A number of font families are specified. The numerical weight values (100 to 900) should show the lighter weights on the lower numbers and the heavier weights on the larger numbers. Heavier is defined to mean 'no lighter'.</p>
+ <p>If only one font weight is available, they should all display at the same weight. The transition from black to green figures shows the correct light to bold transition for the common case where two weights are available. If three or more weights are available, see the CSS2 specification for how these are allocated to the nine weight numbers.</p>
+ <p>The absolute keywords 'normal' and bold' are tested by the first two lines on the right hand side of the test, the third line of text tests the to 'bolder' relative keyword and the fourth tests the 'lighter' relative keyword.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-fonts-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g font-family="Georgia,'Times New Roman',Times,'MS Mincho',serif" font-size="30">
+ <text font-weight="100" x="360" y="50">100</text>
+ <text font-weight="200" x="360" y="85">200</text>
+ <text font-weight="300" x="360" y="120">300</text>
+ <text font-weight="400" x="360" y="155">400</text>
+ <text font-weight="500" x="360" y="190">500</text>
+ <text fill="green" font-weight="600" x="360" y="225">600</text>
+ <text fill="green" font-weight="700" x="360" y="260">700</text>
+ <text fill="green" font-weight="800" x="360" y="295">800</text>
+ <text fill="green" font-weight="900" x="360" y="330">900</text>
+ <text font-weight="bold" x="60" y="80">This is bold</text>
+ <text font-weight="normal" x="60" y="130">This is normal</text>
+ <g font-weight="normal" fill="blue">
+ <text font-weight="bolder" x="60" y="180">Blue is bolder</text>
+ </g>
+ <g font-weight="bold" fill="blue">
+ <text font-weight="lighter" x="60" y="230">Blue is lighter</text>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-03-t.svg
new file mode 100644
index 0000000000..4a15fdba9f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-03-t.svg
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="MI" desc="Testing font-family attribute" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: text-fonts-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Testing font-family attribute. Two SVG fonts are defined. Various text elements are then used with varying values for the font-family attribute. The first two text elements should display in their respective fonts, the last two should be displayed using the system font since the value specified for font-family is either invalid or not specified.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-fonts-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font>
+ <font-face font-family="SVGHaettenschweiler" />
+ <glyph unicode="A" horiz-adv-x="440" d="M440 0l-160 0 -20 180 -80 0 -20 -180 -160 0 120 700 200 0 120 -700zm-200 280l-20 220 -20 -220 40 0z" />
+ <glyph unicode="B" horiz-adv-x="378" d="M20 0l0 700 180 0c40,0 80,0 100,-20 40,-20 60,-60 60,-100l0 -100c0,-60 -40,-80 -100,-100 80,-20 100,-60 100,-100l0 -140c0,-40 -20,-80 -40,-100 -40,-20 -60,-40 -100,-40l-200 0zm200 460l0 120c0,20 -20,20 -40,20l0 -180c20,0 40,0 40,40zm0 -340l0 180c0,20 -20,40 -40,40l0 -260c20,0 40,20 40,40z" />
+ <glyph unicode="C" horiz-adv-x="370" d="M360 460l-140 0 0 140c0,0 -20,20 -20,20 -20,0 -20,-20 -20,-20l0 -500c0,0 0,0 20,0 0,0 20,0 20,0l0 180 140 0 0 -180c0,-20 -20,-60 -60,-80 -20,-20 -60,-20 -100,-20 -120,0 -180,40 -180,120l0 460c0,80 60,120 180,120 100,0 160,-40 160,-120l0 -120z" />
+ </font>
+ <font>
+ <font-face font-family="SVGCharlesworth" />
+ <glyph unicode="A" horiz-adv-x="712" d="M-60 0l0 20c0,0 20,0 40,0 40,0 40,0 60,20 0,0 20,20 40,80 20,60 40,120 80,200 20,80 40,160 80,220 20,60 40,120 40,120 0,20 -20,20 -80,20l0 20c20,0 80,0 140,0 100,0 140,0 160,0l0 -20c-40,0 -80,0 -80,-20 20,-60 60,-140 80,-220 40,-100 80,-180 100,-260 40,-80 60,-140 60,-140 0,0 20,-20 40,-20 40,0 60,0 60,0l0 -20c0,0 -60,0 -180,0 -20,0 -40,0 -80,0 -40,0 -60,0 -80,0l0 20c20,0 60,0 80,0 20,0 20,20 20,20 0,0 -20,60 -40,140 -40,80 -40,120 -60,140 -60,0 -140,0 -220,0 -20,-20 -20,-40 -20,-80 -20,-40 -40,-80 -40,-120 -20,-60 -20,-80 -20,-80 20,-20 60,-20 80,-20l20 -20c-40,0 -80,0 -140,0 -80,0 -120,0 -140,0zm260 360c40,0 80,0 120,0 60,0 100,0 100,0 0,0 0,0 -20,40 0,20 -20,60 -40,100 0,40 -20,80 -20,100 -20,20 -20,40 -20,60l0 0c-20,-40 -40,-80 -60,-160 -40,-80 -60,-120 -60,-140z" />
+ <glyph unicode="B" horiz-adv-x="684" d="M160 660c-20,20 -40,20 -100,20l-20 20c20,0 60,0 120,0 80,0 140,0 180,0 60,0 100,0 160,-20 40,-20 60,-60 60,-100 0,-40 -20,-100 -60,-120 -20,-40 -60,-60 -100,-80l0 0c40,0 60,-20 100,-40 20,0 40,-20 60,-40 20,-20 20,-40 40,-60 0,-20 0,-40 0,-60 0,-40 0,-60 -20,-100 -20,-20 -40,-40 -80,-60 -20,-20 -60,-20 -100,-20 -20,0 -40,0 -80,0 -60,0 -100,0 -160,0 -20,0 -60,0 -120,0l20 20c0,0 20,0 40,0 40,0 40,0 60,20 0,0 0,20 0,80 0,80 0,160 0,240 0,80 0,140 0,200 0,60 0,100 0,100zm120 -620c20,0 60,-20 80,-20 20,0 60,0 80,20 20,0 20,20 40,40 20,20 20,40 20,60 0,40 -20,80 -40,100 -20,40 -40,60 -80,80 -40,20 -60,20 -100,20 0,-20 0,-40 0,-80 0,-40 0,-80 0,-120 0,-40 0,-80 0,-100zm0 340c40,0 80,0 100,20 20,20 40,40 60,60 0,20 0,60 0,80 0,20 0,40 0,60 -20,20 -40,40 -60,60 -20,20 -40,20 -60,20 -20,0 -40,0 -40,0 0,0 0,-20 0,-40 0,-20 0,-60 0,-140 0,-60 0,-100 0,-120z" />
+ <glyph unicode="C" horiz-adv-x="808" d="M740 480l-20 0c0,20 0,60 0,80 -20,20 -20,40 -40,60 -40,20 -60,20 -100,40 -40,20 -60,20 -100,20 -20,0 -20,0 -40,0 -40,0 -100,-20 -120,-40 -40,-20 -60,-40 -80,-80 -20,-20 -40,-40 -60,-80 0,-20 0,-60 0,-80 0,-60 0,-120 20,-160 20,-40 60,-80 100,-120 20,-20 80,-40 120,-60 40,-20 100,-40 140,-40 80,20 160,40 220,60l0 -40c-40,-20 -80,-40 -140,-40 -40,-20 -100,-20 -140,-20 -80,0 -140,20 -200,40 -80,20 -120,60 -180,100 -40,60 -60,120 -60,200 0,0 0,20 0,20 0,60 0,100 20,140 20,40 60,80 100,120 20,40 80,60 140,80 60,20 120,40 200,40 60,0 120,-20 200,-20 0,0 0,0 0,20 20,40 20,40 20,60l20 0c0,-20 0,-60 0,-140 -20,-100 -20,-140 -20,-160z" />
+ </font>
+ </defs>
+ <text x="15" y="60" font-size="18">font-family = "Haettenschweiler"</text>
+ <text x="340" y="60" font-family="SVGHaettenschweiler" font-size="35">ABC</text>
+ <text x="15" y="110" font-size="18">font-family = "Charlesworth"</text>
+ <text x="340" y="110" font-family="SVGCharlesworth" font-size="35">ABC</text>
+ <text x="15" y="160" font-size="18">font-family = "Invalid Name"</text>
+ <text x="340" y="160" font-family="InvalidFontFamily" font-size="35">ABC</text>
+ <text x="15" y="210" font-size="18">font-family = not specified</text>
+ <text x="340" y="210" font-size="35">ABC</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-04-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-04-t.svg
new file mode 100644
index 0000000000..b2459ed12a
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-04-t.svg
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="MI" desc="Testing font-family attribute" status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: text-fonts-04-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Testing font-family attribute.
+ Various text elements are
+ used with varying values for the font-family attribute.
+ The first two text elements should display in their respective fonts,
+ <span style="font-family: Haettenschweiler">Haettenschweiler</span> and
+ <span style="font-family: Charlesworth"></span>,
+ <em>if</em> they are installed on the target system. Otherwise, simply
+ displaying
+ the text in some fallback font is enough to pass the test.
+ The last two should be displayed using a fallback font since the
+ value specified for font-family is either invalid or not specified.
+ Failing to display the text means the test is not passed.
+ </p>
+ <p>
+ If the two named fonts are available on the system,
+ the rendered picture should match the reference image exactly,
+ except for possible
+ variations in the labelling text (per CSS2 rules)
+ and variations in text antialiasing or hinting.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-fonts-04-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <text x="15" y="60" font-size="18">font-family = "Haettenschweiler"</text>
+ <text x="340" y="60" font-family="Haettenschweiler" font-size="35">ABC</text>
+
+ <text x="15" y="110" font-size="18">font-family = "Charlesworth"</text>
+ <text x="340" y="110" font-family="Charlesworth" font-size="35">ABC</text>
+
+ <text x="15" y="160" font-size="18">font-family = "Invalid Name"</text>
+ <text x="340" y="160" font-family="InvalidFontFamily" font-size="35">ABC</text>
+
+ <text x="15" y="210" font-size="18">font-family = not specified</text>
+ <text x="340" y="210" font-size="35">ABC</text>
+
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-202-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-202-t.svg
new file mode 100644
index 0000000000..114819c4f3
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-fonts-202-t.svg
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="DS" owner="CL" desc="Test that viewer has the basic capability to handle different font weights" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: text-fonts-202-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns:xhtml="http://www.w3.org/1999/xhtml">
+ <p>
+ This tests the 'font-weight' property when multiple weights are available. A
+ font family with six weights is specified, with a fallback to 'serif'. If
+ the platform supports installable opentype fonts, please download
+ <a href="http://justanotherfoundry.com/Zalamander/index.htm">Zalamander Caps</a>
+ by Tim Ahrens of <a href="http://justanotherfoundry.com/">Just Another Foundry</a>.
+ </p>
+ <p>
+ The numerical weight values (100 to 900) should show the lighter weights on the
+ lower numbers and the heavier weights on the larger numbers. Heavier is defined
+ to mean 'no lighter'.
+ </p>
+ <p>
+ If only one font weight is available, they should all display at the same weight.
+ The transition from black to green figures shows the correct light to bold transition
+ for the common case where two weights are available. If three or more weights are
+ available, see the CSS2 specification for how these are allocated to the nine weight
+ numbers.
+ </p>
+ <p>
+ The absolute keywords 'normal' and bold' are tested by the first two lines on the
+ right hand side of the test, the third line of text tests the to 'bolder' relative
+ keyword and the fourth tests the 'lighter' relative keyword.
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-fonts-202-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII" font-size="18">
+ <g font-family="'ZalamanderCaps', serif" font-size="30">
+ <text font-weight="100" x="360" y="50">100</text>
+ <text font-weight="200" x="360" y="85">200</text>
+ <text font-weight="300" x="360" y="120">300</text>
+ <text font-weight="400" x="360" y="155">400</text>
+ <text font-weight="500" x="360" y="190">500</text>
+ <text fill="green" font-weight="600" x="360" y="225">600</text>
+ <text fill="green" font-weight="700" x="360" y="260">700</text>
+ <text fill="green" font-weight="800" x="360" y="295">800</text>
+ <text fill="green" font-weight="900" x="360" y="330">900</text>
+ <text font-weight="bold" x="60" y="80">This is bold</text>
+ <text font-weight="normal" x="60" y="130">This is normal</text>
+ <g font-weight="normal" fill="blue">
+ <text font-weight="bolder" x="60" y="180">Blue is bolder</text>
+ </g>
+ <g font-weight="bold" fill="blue">
+ <text font-weight="lighter" x="60" y="230">Blue is lighter</text>
+ </g>
+ <g font-size="14">
+ <text x="30" y="270">ZalamanderCaps is an OpenType font</text>
+ <text x="30" y="290">by Tim Ahrens of Just Another Foundry</text>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-01-t.svg
new file mode 100644
index 0000000000..e16c341c67
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-01-t.svg
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="JF" desc="Test left-to-right aspect of internationalized text." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: text-intro-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test left-to-right aspect of internationalized text.</p>
+ <p>Various text strings in various languages appear. The main purpose of the test is to verify that the correct characters appear and that they appear in the correct order and orientation, even though the first choice font does not have the right glyphs.</p>
+ <p>Correct rendering requires that each character is rendered. it may be rendered with the 'missing glyph' if no glyphs are found in the fonts listed in the content, or in any fallback font that is available. The first choice font is a special SVG font that only contains the 'missing glyph'. Missing glyph from other fonts may conformantly be used, however.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-intro-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font xml:id="Missy" horiz-adv-x="5">
+ <font-face font-family="MissingInAction" font-weight="normal" font-style="normal" units-per-em="8" cap-height="8" x-height="4" ascent="8" descent="2" alphabetic="0" mathematical="4" ideographic="-2" hanging="8" />
+ <missing-glyph d="M1,3h2v2h-2z" />
+ </font>
+ </defs>
+ <text font-family="Arial Unicode MS" font-size="40" fill="red" x="5" y="40">Test left-to-right text.</text>
+ <g font-size="17" font-family="MissingInAction, Georgia, 'Arial Unicode MS', 'LucidaSansUnicode','MS-Gothic'">
+ <text x="10" y="75">Polish: Mogę jeść szkło, i mi ...</text>
+ <text x="10" y="110">Russian: Я могу есть стекло, ...</text>
+ <text x="10" y="145" font-size="17">Greek: Μπορώ να φάω ...</text>
+ <text x="10" y="180">Hebrew: אני יכול לאכול זכוכית ... </text>
+ <text x="10" y="215">Yiddish: איך קען עסן גלאָז און ...</text>
+ </g>
+ <g font-size="17" font-family="MissingInAction, 'MS Song', SimHei,'LucidaSansUnicode', 'Arial Unicode MS'">
+ <text x="10" y="250">Chinese:我能吞下玻璃而不伤身体。</text>
+ </g>
+ <g font-size="17" font-family="MissingInAction, 'MS-Gothic','LucidaSansUnicode', 'Arial Unicode MS'">
+ <text x="10" y="285" font-size="17">Japanese: 私はガラスを食べます。</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-04-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-04-t.svg
new file mode 100644
index 0000000000..cf60f7ed7d
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-04-t.svg
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="JF" desc="Test basic of internationalized text." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: text-intro-04-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test basic aspect of internationalized text.</p>
+ <p>Various text strings in various languages appear. The main purpose of the test is to verify that the correct characters appear and that they appear in the correct order and orientation.</p>
+ <p>Correct rendering requires that each character is rendered. It is not required that a given character be rendered with any particular font; just that it is rendered. It may be rendered with the 'missing glyph' if no glyphs are found in the fonts listed in the content, or in any fallback font that is available.</p>
+ <p>A future version of this test might include all necessary glyphs as an SVG font.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-intro-04-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="16" fill="red" x="10" y="20">Test horizontal text.</text>
+ <g font-size="17" font-family="'Arial Unicode MS', 'LucidaSansUnicode','MS-Gothic'">
+ <text x="10" y="60">Polish: Mogę jeść szkło, i mi nie szkodzi.</text>
+ <text x="10" y="90">Russian: Я могу есть стекло, это мне не вредит.</text>
+ <text x="10" y="120" font-size="15">Greek: Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα.</text>
+ <!-- Greek and japanese smaller just to make it fit on the line -->
+ <text x="10" y="150">Text "אני יכול לאכול זכוכית וזה לא מזיק לי" is in Hebrew</text>
+ <text x="10" y="180">Yiddish: איך קען עסן גלאָז און עס טוט מיר נישט װײ.</text>
+ <text x="10" y="210">Chinese:我能吞下玻璃而不伤身体。</text>
+ <text x="10" y="240" font-size="15">Japanese: 私はガラスを食べられます。それは私を傷つけません。</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-05-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-05-t.svg
new file mode 100644
index 0000000000..463b074e8d
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-05-t.svg
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="ED" owner="CL" desc="Tests Arabic text using various platform fonts" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: text-intro-05-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Tests Arabic text using various platform fonts. If these fonts are not available, a fallback font should be used that has Arabic glyphs. If such a font is not available, the 'missing glyph' (typically an open rectangle) should be displayed. It is an error to display the wrong Arabic glyphs, for example to display all isolate forms.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-intro-05-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="460" y="80" text-anchor="end" xml:lang="ar" font-size="30" font-family="Andalus">لماذا لا يتكلمون اللّغة العربية فحسب؟</text>
+ <!-- andalus font comes with Windows 2000 and XP -->
+ <text x="460" y="160" text-anchor="end" xml:lang="ar" font-size="36" font-family="'Diwani Letter'">لماذا لا يتكلمون اللّغة العربية فحسب؟</text>
+ <!-- Diwani fonts come with Microsoft Arabic fonts extension for Office XP http://www.microsoft.com/downloads/details.aspx?FamilyID=A83C0E03-8913-47A3-ACB7-8AC357627620&displaylang=AR -->
+ <text x="460" y="240" text-anchor="end" xml:lang="ar" font-size="30" font-family="'Nafees Naskh'">لماذا لا يتكلمون اللّغة العربية فحسب؟</text>
+ <!-- Nafees Nastaleeq and Nafees Naskh are freely available from the Center for Research in Urdu Language Processing (CRULP http://www.crulp.org ) at the National University of Computer and Emerging Sciences, Pakistan ( http://www.nu.edu.pk ) -->
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-06-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-06-t.svg
new file mode 100644
index 0000000000..9cd03b1eb4
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-06-t.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AG" owner="CL" desc="test mandatory arabic ligatures" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: text-intro-06-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns:xhtml="http://www.w3.org/1999/xhtml">
+ <p>This test ensures that mandatory ligatures in Arabic are displayed.</p>
+ <p>
+ There are two subtests. The first requires an isolate lam-alef ligature
+ and the second requires a right-joining lam-alef ligature.
+ </p>
+ <p>
+ The test is passed if subtests are displayed as following:
+ </p>
+ <ul>
+ <li>The first subtest has the word for 'tools', آلات</li>
+ <li>The second subtest has the word for 'three', ثلاثة</li>
+ </ul>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-intro-06-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g font-family="Andalus,Diwani Letter,serif">
+ <path d="M10,120 L470,120" stroke="#BBB" />
+ <path d="M10,240 L470,240" stroke="#BBB" />
+ <text text-anchor="middle" x="240" y="120" font-size="140" xml:lang="ar" fill="#700">آلات</text>
+ <text text-anchor="middle" x="240" y="240" font-size="140" xml:lang="ar" fill="#700">ثلاثة</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-201-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-201-t.svg
new file mode 100644
index 0000000000..c6103034b4
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-intro-201-t.svg
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="DS" desc="Test for basic capability to handle 'text' elements and text presentation attributes." status="accepted"
+ approved="yes"
+ version="$Revision: 1.4 $" testname="$RCSfile: text-intro-201-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test text element, tspan element and various text styles.</p>
+ <p>The first group tests that text displays at all, that it displays in a straight line, and that the font style can be made italic or bold.</p>
+ <p>The second group tests that text can be treated as any other graphical element, with stroke and fill properties. The first word tests that fill color can be specified. The second word tests that stroke color can be specified in absence of fill. The third group tests the combination of all these effects. The final group tests positioning of 'text' elements.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-intro-201-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="19" y="61" font-size="32">Plain</text>
+ <text x="142" y="61" font-size="32" font-style="italic">Italic</text>
+ <text x="257" y="60" font-size="32" font-weight="bold">Bold</text>
+ <text x="224" y="110" font-size="32" fill="blue">fill only</text>
+ <text x="39" y="147" font-size="32" fill="none" stroke="red">stroke only</text>
+ <text x="10" y="200" font-size="32" font-style="italic" font-weight="bold" fill="blue" stroke="red">Bold, italic, fill and stroke</text>
+ <g>
+ <rect x="50" y="225" width="380" height="64" fill="none" stroke="black" stroke-width="2" />
+ <g>
+ <text x="55" y="245" font-size="24" fill="black">Each line of text which flows in a </text>
+ <text x="55" y="265" font-size="24" fill="black">rectangular box has to be broken</text>
+ <text x="55" y="285" font-size="24" fill="black">into separated lines.</text>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.4 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-04-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-04-t.svg
new file mode 100644
index 0000000000..c9bb324c42
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-04-t.svg
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="VH" desc="Tests that the viewer can handle the rotate attribute on the text element" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: text-text-04-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The purpose of this test is to validate proper handling of the text element's x and y attributes. In the various samples, a red marker shows the text's (0,0) coordinate. The blue markers show the current text positions. These are either defined by absolute x/y positioning or they are computed from the embeded font's glyphs advances.</p>
+ <p>The first text sample shows a reference piece of text.</p>
+ <p>The second text sample (x all) shows a piece of text where all the glyphs are positioned along the x axis.</p>
+ <p>The third text sample (x more) is a text element where there are more x values than characters (5 values for 4 characters). The last x value should be ignored and the result should be the same as the third sample.</p>
+ <p>The fourth text sample (x fewer) is a text element where there are fewer x values than characters (3 values for 4 characters). The last character should not be positioned but laid out normally, following its previous character sibling.</p>
+ <p>The fifth (y all), sixth (y more) and seventh (y fewer) text sample parallel the second, third and fourth test, but for the y attribute values.</p>
+ <p>The samples in the right column show combinations of x/y value sets.</p>
+ <p>In all the above tests, blue markers represent the expected glyph positions. The red markers are showing positions where no glyph should appear. The glyphs are black squares of increasing sizes.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-text-04-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font xml:id="embeded" horiz-adv-x="224">
+ <font-face font-family="embeded" units-per-em="1000" ascent="1000" descent="-250" alphabetic="0" />
+ <missing-glyph horiz-adv-x="800" d="M50 0V800H750V0H50ZM700 50V750H100V50H700Z" />
+ <glyph unicode="1" glyph-name="gl_1" horiz-adv-x="750" d="M 0 0 L 250 0 L 250 250 L 0 250 Z" />
+ <glyph unicode="2" glyph-name="gl_2" horiz-adv-x="750" d="M 0 0 L 500 0 L 500 500 L 0 500 Z" />
+ <glyph unicode="3" glyph-name="gl_3" horiz-adv-x="750" d="M 0 0 L 750 0 L 750 750 L 0 750 Z" />
+ <glyph unicode="4" glyph-name="gl_4" horiz-adv-x="750" d="M 0 0 L 1000 0 L 1000 1000 L 0 1000 Z" />
+ </font>
+ </defs>
+ <defs>
+ <rect xml:id="marker" x="-4" y="-4" width="8" height="8" />
+ </defs>
+ <g font-size="16">
+ <g xml:id="reference" transform="translate(130, 40)">
+ <text text-anchor="end" x="-30">Reference</text>
+ <g>
+ <use xlink:href="#marker" x="0" fill="#8888FF" />
+ <use xlink:href="#marker" x="15" fill="#8888FF" />
+ <use xlink:href="#marker" x="30" fill="#8888FF" />
+ <use xlink:href="#marker" x="45" fill="#8888FF" />
+ <text xml:id="ref" font-family="embeded" font-size="20">1234</text>
+ </g>
+ </g>
+ <g xml:id="xAll" transform="translate(130, 80)">
+ <text text-anchor="end" x="-30">x all</text>
+ <use xlink:href="#marker" x="0" fill="red" />
+ <use xlink:href="#marker" x="20" fill="#8888FF" />
+ <use xlink:href="#marker" x="40" fill="#8888FF" />
+ <use xlink:href="#marker" x="60" fill="#8888FF" />
+ <use xlink:href="#marker" x="80" fill="#8888FF" />
+ <text font-family="embeded" font-size="20" x="20 40 60 80">1234</text>
+ </g>
+ <g xml:id="xMore" transform="translate(130, 120)">
+ <text text-anchor="end" x="-30">x more</text>
+ <use xlink:href="#marker" x="0" fill="red" />
+ <use xlink:href="#marker" x="20" fill="#8888FF" />
+ <use xlink:href="#marker" x="40" fill="#8888FF" />
+ <use xlink:href="#marker" x="60" fill="#8888FF" />
+ <use xlink:href="#marker" x="80" fill="#8888FF" />
+ <use xlink:href="#marker" x="100" fill="red" />
+ <text font-family="embeded" font-size="20" x="20 40 60 80 100">1234</text>
+ </g>
+ <g xml:id="xFewer" transform="translate(130, 160)">
+ <text text-anchor="end" x="-30">x fewer</text>
+ <use xlink:href="#marker" x="0" fill="red" />
+ <use xlink:href="#marker" x="20" fill="#8888FF" />
+ <use xlink:href="#marker" x="40" fill="#8888FF" />
+ <use xlink:href="#marker" x="60" fill="#8888FF" />
+ <use xlink:href="#marker" x="75" fill="#8888FF" />
+ <text font-family="embeded" font-size="20" x="20 40 60">1234</text>
+ </g>
+ <g xml:id="yAll" transform="translate(130, 200)">
+ <text text-anchor="end" x="-30">y all</text>
+ <use xlink:href="#marker" x="0" y="-10" fill="#8888FF" />
+ <use xlink:href="#marker" x="15" y="-5" fill="#8888FF" />
+ <use xlink:href="#marker" x="30" y="5" fill="#8888FF" />
+ <use xlink:href="#marker" x="45" y="10" fill="#8888FF" />
+ <text font-family="embeded" font-size="20" y="-10 -5 5 10">1234</text>
+ </g>
+ <g xml:id="yMore" transform="translate(130, 250)">
+ <text text-anchor="end" x="-30">y more</text>
+ <use xlink:href="#marker" x="0" y="-10" fill="#8888FF" />
+ <use xlink:href="#marker" x="15" y="-5" fill="#8888FF" />
+ <use xlink:href="#marker" x="30" y="5" fill="#8888FF" />
+ <use xlink:href="#marker" x="45" y="10" fill="#8888FF" />
+ <text font-family="embeded" font-size="20" y="-10 -5 5 10 20">1234</text>
+ </g>
+ <g xml:id="yFewer" transform="translate(130, 300)">
+ <text text-anchor="end" x="-30">y fewer</text>
+ <use xlink:href="#marker" x="0" y="-10" fill="#8888FF" />
+ <use xlink:href="#marker" x="15" y="-5" fill="#8888FF" />
+ <use xlink:href="#marker" x="30" y="5" fill="#8888FF" />
+ <use xlink:href="#marker" x="45" y="5" fill="#8888FF" />
+ <text font-family="embeded" font-size="20" y="-10 -5 5">1234</text>
+ </g>
+ <g transform="translate(220, 0)">
+ <g xml:id="xyAll" transform="translate(130, 80)">
+ <text text-anchor="end" x="-30">x/y all</text>
+ <use xlink:href="#marker" x="0" fill="red" />
+ <use xlink:href="#marker" x="20" y="-10" fill="#8888FF" />
+ <use xlink:href="#marker" x="40" y="-5" fill="#8888FF" />
+ <use xlink:href="#marker" x="60" y="5" fill="#8888FF" />
+ <use xlink:href="#marker" x="80" y="10" fill="#8888FF" />
+ <text font-family="embeded" font-size="20" x="20 40 60 80" y="-10 -5 5 10">1234</text>
+ </g>
+ <g xml:id="xyMore" transform="translate(130, 120)">
+ <text text-anchor="end" x="-30">x/y more</text>
+ <use xlink:href="#marker" x="0" fill="red" />
+ <use xlink:href="#marker" x="20" y="-10" fill="#8888FF" />
+ <use xlink:href="#marker" x="40" y="-5" fill="#8888FF" />
+ <use xlink:href="#marker" x="60" y="5" fill="#8888FF" />
+ <use xlink:href="#marker" x="80" y="10" fill="#8888FF" />
+ <use xlink:href="#marker" x="100" y="20" fill="red" />
+ <text font-family="embeded" font-size="20" x="20 40 60 80 100" y="-10 -5 5 10 20">1234</text>
+ </g>
+ <g xml:id="xyFewer" transform="translate(130, 160)">
+ <text text-anchor="end" x="-30">x/y fewer</text>
+ <use xlink:href="#marker" x="0" fill="red" />
+ <use xlink:href="#marker" x="20" y="-10" fill="#8888FF" />
+ <use xlink:href="#marker" x="40" y="-5" fill="#8888FF" />
+ <use xlink:href="#marker" x="60" y="5" fill="#8888FF" />
+ <use xlink:href="#marker" x="75" y="5" fill="#8888FF" />
+ <text font-family="embeded" font-size="20" x="20 40 60" y="-10 -5 5">1234</text>
+ </g>
+ <g xml:id="xAllyFewer" transform="translate(130, 200)">
+ <text text-anchor="end" x="-30">x all y fewer</text>
+ <use xlink:href="#marker" x="0" fill="red" />
+ <use xlink:href="#marker" x="20" y="-10" fill="#8888FF" />
+ <use xlink:href="#marker" x="40" y="-5" fill="#8888FF" />
+ <use xlink:href="#marker" x="60" y="5" fill="#8888FF" />
+ <use xlink:href="#marker" x="80" y="5" fill="#8888FF" />
+ <text font-family="embeded" font-size="20" x="20 40 60 80" y="-10 -5 5">1234</text>
+ </g>
+ <g xml:id="xFewerYall" transform="translate(130, 240)">
+ <text text-anchor="end" x="-30">x fewer y all</text>
+ <use xlink:href="#marker" x="0" fill="red" />
+ <use xlink:href="#marker" x="20" y="-10" fill="#8888FF" />
+ <use xlink:href="#marker" x="40" y="-5" fill="#8888FF" />
+ <use xlink:href="#marker" x="60" y="5" fill="#8888FF" />
+ <use xlink:href="#marker" x="77.52" y="10" fill="#8888FF" />
+ <text font-family="embeded" font-size="20" x="20 40 60" y="-10 -5 5 10">1234</text>
+ </g>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-06-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-06-t.svg
new file mode 100644
index 0000000000..09892b1cea
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-06-t.svg
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="VH" desc="x/y glyph positioning on ligatures" status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: text-text-06-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>The purpose of this test is to validate the interaction of x/y glyph positioning and ligatures.</p>
+ <p>The first line shows an example where there is a ligature (fi) which should be accounted for before breaking into text chunks (see specification section 10.5, additional x/y/dx/dy processing rules, bullet discussing ligatures). In this first line, the ligatures cause the x position 180 (shown in red), to be ignored. As a result, a glyph should be shown over each pale blue square markers. The glyphs are black squares of increasing sizes except for the initial ligature which has the form of two small black triangles joined at their tops. The ligature should show on the first pale blue marker position.</p>
+ <p>The second line shows the same test but using multiple y positions.</p>
+ <p>The third line shows the same test but using multiple x and y positions.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-text-06-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <font xml:id="embeded" horiz-adv-x="224">
+ <font-face font-family="embeded" units-per-em="1000" panose-1="0 0 0 0 0 0 0 0 0 0" ascent="917" descent="-250" alphabetic="0" />
+ <missing-glyph horiz-adv-x="800" d="M50 0V800H750V0H50ZM700 50V750H100V50H700Z" />
+ <glyph unicode="1" glyph-name="gl_1" horiz-adv-x="1500" d="M 0 0 L 250 0 L 250 250 L 0 250 Z" />
+ <glyph unicode="2" glyph-name="gl_2" horiz-adv-x="1500" d="M 0 0 L 500 0 L 500 500 L 0 500 Z" />
+ <glyph unicode="3" glyph-name="gl_3" horiz-adv-x="1500" d="M 0 0 L 750 0 L 750 750 L 0 750 Z" />
+ <glyph unicode="4" glyph-name="gl_4" horiz-adv-x="1500" d="M 0 0 L 1000 0 L 1000 1000 L 0 1000 Z" />
+ <glyph unicode="fi" glyph-name="fi" horiz-adv-x="1500" d="M 0 0 L 500 0 L 0 700 L 500 700 Z" />
+ </font>
+ </defs>
+ <defs>
+ <g xml:id="marker">
+ <line y2="-15" stroke="red" />
+ <rect x="-4" y="-4" width="8" height="8" />
+ </g>
+ </defs>
+ <g font-size="10">
+ <g transform="translate(20, 30)">
+ <g xml:id="legend" transform="translate(10, 40)" font-size="12">
+ <text>x positioning</text>
+ <text y="40">y positioning</text>
+ <text y="140">x/y positioning</text>
+ </g>
+ <g transform="translate(100, 40)">
+ <use xlink:href="#marker" x="10" fill="#8888ff" />
+ <use xlink:href="#marker" x="180" fill="red" />
+ <use xlink:href="#marker" x="40" fill="#8888ff" />
+ <use xlink:href="#marker" x="70" fill="#8888ff" />
+ <use xlink:href="#marker" x="100" fill="#8888ff" />
+ <use xlink:href="#marker" x="130" fill="#8888ff" />
+ <text x="10 180 40 70 100 130" y="0" font-family="embeded">fi1234</text>
+ </g>
+ <g transform="translate(100, 80)">
+ <use xlink:href="#marker" y="-10" fill="#8888ff" />
+ <use xlink:href="#marker" x="15" y="50" fill="red" />
+ <use xlink:href="#marker" x="15" y="0" fill="#8888ff" />
+ <use xlink:href="#marker" x="30" y="10" fill="#8888ff" />
+ <use xlink:href="#marker" x="45" y="20" fill="#8888ff" />
+ <use xlink:href="#marker" x="60" y="30" fill="#8888ff" />
+ <text y="-10 50 0 10 20 30" x="0" font-family="embeded">fi1234</text>
+ </g>
+ <g transform="translate(100, 180)">
+ <use xlink:href="#marker" x="10" y="-10" fill="#8888ff" />
+ <use xlink:href="#marker" x="180" y="50" fill="red" />
+ <use xlink:href="#marker" x="40" y="0" fill="#8888ff" />
+ <use xlink:href="#marker" x="70" y="10" fill="#8888ff" />
+ <use xlink:href="#marker" x="100" y="20" fill="#8888ff" />
+ <use xlink:href="#marker" x="130" y="30" fill="#8888ff" />
+ <text x="10 180 40 70 100 130" y="-10 50 0 10 20 30" font-family="embeded">fi1234</text>
+ </g>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-07-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-07-t.svg
new file mode 100644
index 0000000000..7a52266c13
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-07-t.svg
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="MI" desc="Tests multiple x, y, rotate" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: text-text-07-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Tests multiple x, y, rotate, with various combinations. Since an array of values is given, each glyph must use the value from the corresponding character in the list.</p>
+ <p>The rendered picture should match the reference image exactly, except for possible variations in the labelling text (per CSS2 rules).</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-text-07-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="240 260 280 300 320 340 360" y="60 80 100 120 140 160 180 200" font-size="35">Multi X Y</text>
+ <text x="10" y="60" rotate="0 10 20 30 40 50 60" font-size="35">ROTATE</text>
+ <text x="10 30 50 70 90 110 130 150 170 190 210 230 250" y="300 290 280 270 260 250 240 230 220 210 200 190 180" rotate="0 -10 -20 -30 -40 -50 -60 -70 -80 -90 -100 -110 -120" font-size="35">Both Together</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-08-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-08-t.svg
new file mode 100644
index 0000000000..b83966ba60
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-08-t.svg
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="DJ" owner="SH" desc="tests text opacity properties" status="accepted"
+ approved="yes"
+ version="$Revision" testname="$RCSfile: text-text-08-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Two opacity properties (fill-opacity and stroke-opacity) of 'text' elements are covered in this test.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-text-08-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="19" y="60" font-size="64" fill="blue" stroke="red" stroke-width="2">Normal Text</text>
+ <text x="19" y="120" font-size="64" fill="blue" stroke="red" stroke-width="2" fill-opacity="0.50">Fill opacity</text>
+ <text x="19" y="180" font-size="64" fill="blue" stroke="red" stroke-width="2" stroke-opacity="0.50">Stroke opacity</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-09-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-09-t.svg
new file mode 100644
index 0000000000..caa1bbe412
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-text-09-t.svg
@@ -0,0 +1,55 @@
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="AE" owner="CL" desc="Tests multiple x, y, rotate" status="accepted"
+ approved="yes"
+ version="$Revision: 1.6 $" testname="$RCSfile: text-text-09-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Tests multiple x, y, rotate, with various combinations. Since an
+ array of values is given, each glyph must use the value from the
+ corresponding character in the list. In this test, there are less values
+ in the array than there are characters.
+ <!-- publish once the eratta are out -->
+ </p>
+ <p>
+ The rendered picture should match the reference image exactly, except for possible
+ variations in the labelling text (per CSS2 rules).
+ </p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-text-09-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="240 260 280 300" y="60 80 100 120 140" font-size="35">Multi X Y</text>
+ <text x="10" y="60" rotate="0 10 20 30" font-size="35">ROTATE</text>
+ <text x="10 30 50 70 90 110 130 150" y="300 290 280 270 260 250 240 230" rotate="0 -10 -20 -30 -40 -50 -60 -70 -80 -90" font-size="35">Both Together</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-tselect-03-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-tselect-03-t.svg
new file mode 100644
index 0000000000..32378bd0cb
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-tselect-03-t.svg
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="CL" owner="ED" desc="Tests bidirectional text selection" status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: text-tselect-03-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ This test demonstrates text selection of bidirectional text.
+ </p>
+ <p>To pass the test the the first 9 characters in logical order starting from logical position 0 are to be selected. This must be done by the tester since there's no way to control the selection in DOM. The selection should be started at the letter 'a' and proceed to the number '1' as indicated by the arrows. Visually this makes the selection discontigous and these substrings must be selected (listed in visual order):</p>
+ <p>"abc"</p>
+ <p>the space between "c" and "&#1493;"</p>
+ <p>"1"</p>
+ <p>the space between "3" and "&#1490;"</p>
+ <p>"&#1488;&#1489;&#1490;"</p>
+ <p>If only the substrings listed above were selected then the test has passed.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-tselect-03-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ <font xml:id="mini" horiz-adv-x="500" >
+ <font-face
+ font-family="tselect"
+ font-weight="400"
+ font-stretch="normal"
+ units-per-em="1000"
+ panose-1="2 2 6 3 5 4 5 2 3 4"
+ ascent="800"
+ descent="-200"
+ x-height="450"
+ cap-height="686"
+ bbox="-797 -545 2010 1166"
+ underline-thickness="50"
+ underline-position="-100"
+ unicode-range="U+05D0-U+05D5, U+0061-U+0066, U+0020, U+0031-U+0033" />
+ <missing-glyph horiz-adv-x="432" d="M33 0v666h333v-666h-333zM66 33h267v600h-267v-600z" />
+ <glyph glyph-name="one" unicode="1" d="M183 593q-18 0 -72 -22v14l180 91l8 -2v-600q0 -36 18 -47t77 -12v-15h-276v15q56 2 75.5 16.5t19.5 61.5v453q0 47 -30 47z" />
+ <glyph glyph-name="two" unicode="2" d="M31 477q5 23 10 40t21.5 49.5t37 54t57 38.5t82.5 17q78 0 131.5 -51t53.5 -126q0 -113 -128 -247l-168 -176h239q34 0 50.5 11.5t44.5 54.5l13 -5l-55 -137h-390v12l178 189q130 138 130 260q0 63 -39 102t-102 39q-52 0 -83.5 -28.5t-61.5 -101.5z" />
+ <glyph glyph-name="three" unicode="3" d="M81 78q23 0 68.5 -28t79.5 -28q55 0 93 43t38 106q0 52 -27 91.5t-74 56.5q-29 11 -106 11v13q34 12 58.5 23.5t51.5 31t41.5 47.5t14.5 64q0 47 -30.5 77t-79.5 30q-47 0 -82.5 -25.5t-66.5 -80.5l-15 4q26 71 70.5 116.5t126.5 45.5q69 0 112.5 -38t43.5 -99q0 -41 -21 -72t-73 -66q60 -26 94 -66.5t34 -115.5q0 -106 -78.5 -169.5t-197.5 -63.5q-52 0 -82.5 15.5t-30.5 41.5q0 16 10.5 25.5t27.5 9.5z" />
+ <glyph glyph-name="a" unicode="a" horiz-adv-x="444" d="M37 97q0 38 21.5 69t57 50.5t80 39t91.5 36.5v61q0 83 -76 83q-30 0 -51 -14.5t-21 -34.5q0 -8 2.5 -22t2.5 -18q0 -17 -13.5 -29.5t-31.5 -12.5q-17 0 -30 13t-13 30q0 47 48.5 79.5t119.5 32.5q82 0 113 -39.5t31 -120.5v-195q0 -33 6.5 -45.5t23.5 -12.5q21 0 44 19v-26q-26 -29 -45.5 -39.5t-44.5 -10.5q-31 0 -45.5 17t-18.5 56q-86 -73 -146 -73q-46 0 -75.5 30t-29.5 77zM287 123v145q-90 -33 -126 -64t-36 -75v-4q0 -32 18.5 -54.5t44.5 -22.5q34 0 73 23q16 9 21 19t5 33z" />
+ <glyph glyph-name="b" unicode="b" d="M153 681v-306q15 37 54 61t85 24q75 0 125.5 -62.5t50.5 -154.5q0 -107 -67.5 -180t-166.5 -73q-60 0 -112.5 20.5t-52.5 43.5v519q0 31 -9.5 41t-39.5 10q-11 0 -17 -1v16l29 8q67 19 116 36zM153 322v-252q0 -19 29 -33.5t68 -14.5q62 0 96 46t34 129q0 91 -34.5 145.5t-93.5 54.5q-39 0 -69 -23t-30 -52z" />
+ <glyph glyph-name="c" unicode="c" horiz-adv-x="444" d="M25 213q0 111 65.5 179t153.5 68q63 0 108.5 -30.5t45.5 -72.5q0 -17 -14 -29.5t-34 -12.5q-34 0 -47 46l-6 22q-8 28 -20 38t-39 10q-61 0 -98.5 -48.5t-37.5 -125.5q0 -86 43.5 -140.5t111.5 -54.5q43 0 74 21t67 73l14 -9q-10 -20 -17.5 -33t-27 -39t-38.5 -42t-50 -29.5t-64 -13.5q-83 0 -136.5 62.5t-53.5 160.5z" />
+ <glyph glyph-name="d" unicode="d" d="M344 -10l-4 3v64q-48 -67 -128 -67q-83 0 -134 59.5t-51 155.5q0 106 61 180.5t147 74.5q54 0 105 -43v156q0 31 -9 41t-37 10q-14 0 -22 -1v16q91 24 147 44l5 -2v-567q0 -35 8.5 -46t35.5 -11q5 0 23 1v-16zM251 42q38 0 63.5 21.5t25.5 38.5v230q0 40 -31 70t-71 30q-57 0 -91 -51t-34 -136q0 -92 38 -147.5t100 -55.5z" />
+ <glyph glyph-name="e" unicode="e" horiz-adv-x="444" d="M97 277q2 -63 17 -108.5t39 -68t48.5 -32t51.5 -9.5q48 0 83.5 24t71.5 81l16 -7q-31 -81 -86 -124t-126 -43q-86 0 -136.5 60.5t-50.5 163.5q0 111 58.5 178.5t150.5 67.5q76 0 118 -45.5t53 -137.5h-308zM99 309h204q-10 65 -31 90t-67 25q-90 0 -106 -115z" />
+ <glyph glyph-name="f" unicode="f" horiz-adv-x="333" d="M341 580q-16 0 -27.5 11.5t-18 26t-20 26t-32.5 11.5q-57 0 -57 -89v-116h123v-32h-122v-314q0 -56 16 -71.5t77 -17.5v-15h-260v15q54 3 68.5 18.5t14.5 70.5v314h-82v32h82q2 112 42 172.5t134 60.5q45 0 74.5 -17.5t29.5 -44.5q0 -17 -12.5 -29t-29.5 -12z" />
+ <glyph glyph-name="afii57664" unicode="&#x5d0;" horiz-adv-x="537" d="M71 51q0 14 -18.5 81.5t-18.5 88.5q0 51 63 123q-5 1 -15 8.5t-23 22t-22.5 44t-9.5 66.5q0 36 19 66t38 30h2q2 0 2.5 -3t1.5 -14t4 -24q9 -34 57.5 -84t92.5 -83t49 -33l51 71q-8 0 -45.5 34.5t-37.5 59.5t22 52t43 27q6 0 6.5 -4t-0.5 -11v-6q0 -21 24.5 -41t53.5 -35t53.5 -40t24.5 -55q0 -40 -28 -70.5t-46 -30.5q-1 0 -11 47q-4 20 -14 35t-18 20l-8 5l-49 -77q2 0 20 -10.5t43.5 -31.5t50.5 -47t42.5 -62t17.5 -71q0 -62 -12 -83t-32 -21h-7q-1 0 -2.5 19t-16.5 50t-46 55q-64 47 -161.5 129t-98.5 82l-9 -7q-9 -7 -18.5 -22.5t-9.5 -33.5q0 -23 20 -52t43.5 -52t43.5 -53.5t20 -56.5q0 -18 -10.5 -30.5t-23.5 -17t-24 -10.5h-115l6 12q1 3 6 3q8 0 12 1.5t9 5t7 12t2 22.5z" />
+ <glyph glyph-name="afii57665" unicode="&#x5d1;" horiz-adv-x="537" d="M115 442q-40 0 -60 16.5t-20 70.5q0 55 28 69q0 -3 4 -10.5t19 -16t37 -8.5h206q48 0 83.5 -30.5t35.5 -110.5l2 -314h54l-35 -108h-445l35 108h370v260q0 46 -24.5 60t-72.5 14h-217z" />
+ <glyph glyph-name="afii57666" unicode="&#x5d2;" horiz-adv-x="350" d="M141 433q-26 0 -38.5 16t-12.5 62q0 66 19 87q0 -1 2.5 -5t7 -10.5l7.5 -10.5q6 -9 33.5 -10.5t57 -7t39.5 -24.5q13 -22 13 -69v-22v-264q0 -44 8.5 -89t18.5 -86q-25 0 -32 2t-9.5 10.5t-2.5 25.5q-2 15 -12.5 59.5t-10.5 45.5h-10l-62 -143h-118v4q0 101 30 104l120 21q7 7 24.5 30t18.5 36q2 24 11.5 83.5t9.5 78.5q0 9 -1 13v4q0 23 -12 43.5t-42 20.5q-9 0 -28.5 -2.5t-28.5 -2.5z" />
+ <glyph glyph-name="afii57667" unicode="&#x5d3;" horiz-adv-x="537" d="M53 596q0 -7 13.5 -20.5t42.5 -13.5h315q22 0 40 -16.5t18 -38.5q0 -26 -13.5 -45.5t-35.5 -19.5h-10v-350q0 -4 0.5 -9.5t0.5 -8.5q0 -16 -11 -46t-25 -30h-2l-2 1q-1 0 -1 10q0 3 0.5 12.5t0.5 14.5l9 406h-281q-49 0 -68 20.5t-19 60.5q0 56 28 73z" />
+ <glyph glyph-name="afii57668" unicode="&#x5d4;" horiz-adv-x="537" d="M52 598q0 -5 3.5 -12t17 -15t35.5 -8h315q19 0 30.5 -16.5t11.5 -39.5q0 -65 -42 -65h-10l5 -343q0 -3 3 -17.5t3 -23.5q0 -14 -8.5 -37t-20.5 -23q-5 0 -8 2q-1 0 -1 6q0 4 0.5 14t0.5 15l5 407h-280q-90 0 -90 86q0 49 30 70zM74 142q0 -25 2 -54.5t2 -31.5q0 -21 -6.5 -39t-20.5 -18l-1 1h-3q-7 0 -7 50q0 3 0.5 15t0.5 26q0 13 -1 37t-1 36q0 61 14.5 104t28.5 43q6 0 6 -19q0 -9 -7 -59t-7 -91z" />
+ <glyph glyph-name="afii57669" unicode="&#x5d5;" horiz-adv-x="350" d="M166 563q49 0 63.5 -19t14.5 -59q0 -9 -0.5 -24.5t-0.5 -21.5l12 -340q0 -22 -6 -60.5t-16 -38.5h-2q-1 0 -8 15t-7 25l7 325v7q0 20 -23 46.5t-56 26.5q-6 0 -18 -0.5t-17 -0.5q-28 0 -44.5 17.5t-16.5 44.5q0 24 12 52t23 40l3 -10q3 -11 10.5 -18t21.5 -7q4 0 10 -0.5t9 -0.5q6 0 15.5 0.5t13.5 0.5z" />
+ <glyph glyph-name="space" unicode=" " horiz-adv-x="250"/>
+ </font>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="12" y="300" x="10">Start selecting here</text>
+ <text font-size="12" y="130" x="10">select from 'a' to '1'</text>
+ <path d="M0 100l0 -100m-2 20l2 -20l2 20" transform="translate(20 190)" stroke="black" fill="none"/>
+ <path d="M20 140l160 0m-20 -2l20 2l-20 2" stroke="black" fill="none"/>
+
+ <text xml:id="text" font-size="48" y="128" x="10" font-family="tselect" transform="translate(0 60)"> abc &#1488;&#1489;&#1490; 123 &#1491;&#1492;&#1493; def </text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-ws-01-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-ws-01-t.svg
new file mode 100644
index 0000000000..2b3e92e15c
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-ws-01-t.svg
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="VH" owner="LH," desc="Test that viewer correctly handle whitespace and the 'space' attribute." status="accepted"
+ approved="yes"
+ version="$Revision: 1.7 $" testname="$RCSfile: text-ws-01-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test for viewer correct handling of whitespace and the 'xml:space' attribute. There are two sub-tests, for xml:space value "default". In each test, the content of the 'text' element is written on multiple lines. The first test of each pair has indented text with leading space characters, tabs, etc. The second has no indentation, but a line break before the content and after it. There are no space (or other whitespace) characters at the ends of the lines.</p>
+ <p>The two test cases are self-descriptive. From the top; first, "default" value applied to 3 lines of content with indents, space characters, tabs, etc; second, "default" applied to two lines content with no indent;</p>
+ <p>In each test, the test string is in blue and the reference image is in black. The rendered picture should approximately match the reference image, however there is some question in the reference image concerning the exact amount of space in the long-space areas. The third test uses the nbsp unicode character to force the reference white spaces display, which provides an accurate match if the font in use has the same metrics for that character and the default white space. Also, variations are possible in the text fonts and layout (per CSS2 rules).</p>
+ <p>The test also uses the 'rect' element, as well as basic fill (solid primary colors), stroke (black 1-pixel lines), font-family (Arial) and font-size properties.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-ws-01-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="15" y="35" font-size="32" fill="black">Basic: xml:space attribute</text>
+ <text x="35" y="60" font-size="32" fill="black">&amp; whitespace handling.</text>
+ <!-- Test 1: indented, spaces, tabs, and space='default' -->
+ <!-- Features=" line break and spaces before 1st line" tabs before 2nd line; -->
+ <!-- spaces before 3rd line; no space at ends of any lines. -->
+ <text x="15" y="105" fill="blue" font-size="40" xml:space="default">WS with indented lines.</text>
+ <text x="15" y="140" fill="black" font-size="40">WS with indented lines.</text>
+ <rect x="25" y="145" width="350" height="36" fill="none" stroke="black" />
+ <text x="28" y="175" fill="black" font-size="40">xml:space='default'</text>
+ <!-- Test 2: non-indented,and space='default' -->
+ <!-- Features=" line break before 1st line" no space either at beginning -->
+ <!-- or end of any lines. -->
+ <text x="15" y="225" fill="blue" font-size="40" xml:space="default"> WS non-indented lines. </text>
+ <text x="15" y="260" fill="black" font-size="40">WS non-indented lines.</text>
+ <rect x="25" y="265" width="350" height="36" fill="none" stroke="black" />
+ <text x="28" y="295" fill="black" font-size="40">xml:space='default'</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-ws-02-t.svg b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-ws-02-t.svg
new file mode 100644
index 0000000000..6971cde902
--- /dev/null
+++ b/tests/baseline/scenegraph/data/shared/svg_12_testsuite/text-ws-02-t.svg
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.2" baseProfile="tiny" xml:id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xe="http://www.w3.org/2001/xml-events">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <SVGTestCase xmlns="http://www.w3.org/2000/02/svg/testsuite/description/"
+ reviewer="VH" owner="LH," desc="Test that viewer correctly handle whitespace and the 'space' attribute." status="accepted"
+ approved="yes"
+ version="$Revision: 1.8 $" testname="$RCSfile: text-ws-02-t.svg,v $">
+ <d:OperatorScript xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/" xmlns="http://www.w3.org/1999/xhtml">
+ <p>Test for viewer correct handling of whitespace and the 'xml:space' attribute. There are two sub-tests, for value "preserve". In each test, the content of the 'text' element is written on multiple lines. The first test of each pair has indented text with leading space characters, tabs, etc. The second has no indentation, but a line break before the content and after it. There are no space (or other whitespace) characters at the ends of the lines.</p>
+ <p>The two test cases are self-descriptive. From the top; first, "preserve" applied to essentially the same content as first; second, "preserve" applied to essentially the same content as second.</p>
+ <p>In each test, the test string is in blue and the reference image is in black. The rendered picture should approximately match the reference image, however there is some question in the reference image concerning the exact amount of space in the long-space areas. The third test uses the nbsp unicode character to force the reference white spaces display, which provides an accurate match if the font in use has the same metrics for that character and the default white space. Also, variations are possible in the text fonts and layout (per CSS2 rules).</p>
+ <p>The test also uses the 'rect' element, as well as basic fill (solid primary colors), stroke (black 1-pixel lines), font-family (Arial) and font-size properties.</p>
+ </d:OperatorScript>
+ </SVGTestCase>
+ <title xml:id="test-title">$RCSfile: text-ws-02-t.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../images/SVGFreeSans.svg#ascii" />
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g xml:id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="15" y="35" font-size="32" fill="black">Basic: xml:space attribute</text>
+ <text x="35" y="60" font-size="32" fill="black">&amp; whitespace handling.</text>
+ <!-- Test 3: indented, spaces, tabs, and space='preserve' -->
+ <!-- Features=" line break and spaces before 1st line" tabs before 2nd line; -->
+ <!-- spaces before 3rd line; no space at ends of any lines. -->
+ <text x="15" y="105" fill="blue" font-size="40" xml:space="preserve">
+WS
+ with
+ indented lines.
+ </text>
+ <!-- should match this, with blank replacing HT, LF, etc -->
+ <text x="15" y="140" fill="black" font-size="40" xml:space="preserve">&#160;WS&#160;&#160;&#160;with&#160;&#160;indented&#160;lines.</text>
+ <rect x="25" y="145" width="380" height="36" fill="none" stroke="black" />
+ <text x="28" y="175" fill="black" font-size="40">xml:space='preserve'</text>
+ <!-- Test 4: non-indented, and space='preserve' -->
+ <!-- Features=" no line break before 1st line" no space either at beginning -->
+ <!-- or end of any lines. -->
+ <text x="15" y="225" fill="blue" font-size="40" xml:space="preserve">WS
+non-indented lines.
+ </text>
+ <text x="15" y="260" fill="black" font-size="40">WS non-indented lines.</text>
+ <rect x="25" y="265" width="380" height="36" fill="none" stroke="black" />
+ <text x="28" y="295" fill="black" font-size="40">xml:space='preserve'</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text xml:id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect xml:id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000" />
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g xml:id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1" />
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240" text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/baseline/scenegraph/data/text/text_prefertypolinemetrics.qml b/tests/baseline/scenegraph/data/text/text_prefertypolinemetrics.qml
new file mode 100644
index 0000000000..3bb9452021
--- /dev/null
+++ b/tests/baseline/scenegraph/data/text/text_prefertypolinemetrics.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.0
+
+Item {
+ width: 180
+ height: 60
+
+ Row {
+ anchors.fill: parent
+ Text {
+ font.family: "Arial"
+ font.pixelSize: 16
+ textFormat: Qt.RichText
+ text: "First line<br />Second line<br />Third line"
+ }
+ Text {
+ font.family: "Arial"
+ font.pixelSize: 16
+ textFormat: Qt.RichText
+ text: "First line<br />Second line<br />Third line"
+ font.preferTypoLineMetrics: true
+ }
+
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/coordsOther.qml b/tests/baseline/scenegraph/data/vectorimages/coordsOther.qml
new file mode 100644
index 0000000000..93901e77f7
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/coordsOther.qml
@@ -0,0 +1,38 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 650
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: ListModel {
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/coords-constr-201-t.svg"
+ }
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/coords-coord-01-t.svg"
+ }
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/coords-units-01-t.svg"
+ }
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/coords-viewattr-05-t.svg"
+ }
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/coordsOtherCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/coordsOtherCurveRenderer.qml
new file mode 100644
index 0000000000..e529b0ae5c
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/coordsOtherCurveRenderer.qml
@@ -0,0 +1,38 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 650
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: ListModel {
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/coords-constr-201-t.svg"
+ }
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/coords-coord-01-t.svg"
+ }
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/coords-units-01-t.svg"
+ }
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/coords-viewattr-05-t.svg"
+ }
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/coordsTrans.qml b/tests/baseline/scenegraph/data/vectorimages/coordsTrans.qml
new file mode 100644
index 0000000000..e007c1e05c
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/coordsTrans.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 650
+
+ Grid {
+ columns: 3
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "coords-trans*.svg"]
+ }
+
+ VectorImage {
+ width: 266
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/coordsTransCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/coordsTransCurveRenderer.qml
new file mode 100644
index 0000000000..ce2a3bde02
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/coordsTransCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 650
+
+ Grid {
+ columns: 3
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "coords-trans*.svg"]
+ }
+
+ VectorImage {
+ width: 266
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/fillMode.qml b/tests/baseline/scenegraph/data/vectorimages/fillMode.qml
new file mode 100644
index 0000000000..03e575daf4
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/fillMode.qml
@@ -0,0 +1,59 @@
+import QtQuick
+import QtQuick.VectorImage
+
+Rectangle{
+ id: topLevelItem
+ width: 200
+ height: 880
+
+ Column {
+ anchors.fill: parent
+ Repeater {
+ model: ListModel {
+ ListElement {
+ name: "Stretch"
+ mode: VectorImage.Stretch
+ }
+ ListElement {
+ name: "NoResize"
+ mode: VectorImage.NoResize
+ }
+ ListElement {
+ name: "PreserveAspectCrop"
+ mode: VectorImage.PreserveAspectCrop
+ }
+ ListElement {
+ name: "PreserveAspectFit"
+ mode: VectorImage.PreserveAspectFit
+ }
+
+ }
+
+ Column {
+ width: 200
+ height: 200 + t.height
+ Rectangle {
+ color: "white"
+ border.width: 1
+ border.color: "black"
+ width: 152
+ height: 202
+ VectorImage {
+ x: 1
+ y: 1
+ width: 150
+ height: 200
+ source: "../shared/qt_logo.svg"
+ fillMode: mode
+ clip: true
+ z: 100
+ }
+ }
+ Text {
+ id: t
+ text: name
+ }
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/fontsElem.qml b/tests/baseline/scenegraph/data/vectorimages/fontsElem.qml
new file mode 100644
index 0000000000..5070eb1a88
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/fontsElem.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "fonts-elem*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/fontsElemCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/fontsElemCurveRenderer.qml
new file mode 100644
index 0000000000..1883258f27
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/fontsElemCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "fonts-elem*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/fontsGlyph.qml b/tests/baseline/scenegraph/data/vectorimages/fontsGlyph.qml
new file mode 100644
index 0000000000..b95d5027e3
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/fontsGlyph.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 500
+
+ Grid {
+ columns: 3
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "fonts-glyph*.svg"]
+ }
+
+ VectorImage {
+ width: 266
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/fontsGlyphCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/fontsGlyphCurveRenderer.qml
new file mode 100644
index 0000000000..b7372ad98d
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/fontsGlyphCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 500
+
+ Grid {
+ columns: 3
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "fonts-glyph*.svg"]
+ }
+
+ VectorImage {
+ width: 266
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/fontsOther.qml b/tests/baseline/scenegraph/data/vectorimages/fontsOther.qml
new file mode 100644
index 0000000000..053a873c21
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/fontsOther.qml
@@ -0,0 +1,35 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 650
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: ListModel {
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/fonts-desc-02-t.svg"
+ }
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/fonts-kern-01-t.svg"
+ }
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/fonts-overview-201-t.svg"
+ }
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/fontsOtherCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/fontsOtherCurveRenderer.qml
new file mode 100644
index 0000000000..5f438d24b2
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/fontsOtherCurveRenderer.qml
@@ -0,0 +1,35 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 650
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: ListModel {
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/fonts-desc-02-t.svg"
+ }
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/fonts-kern-01-t.svg"
+ }
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/fonts-overview-201-t.svg"
+ }
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/gradientxform.qml b/tests/baseline/scenegraph/data/vectorimages/gradientxform.qml
new file mode 100644
index 0000000000..3480b4e581
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/gradientxform.qml
@@ -0,0 +1,25 @@
+import QtQuick
+import QtQuick.VectorImage
+
+Rectangle {
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ ListModel {
+ id: renderers
+ ListElement { renderer: VectorImage.GeometryRenderer }
+ ListElement { renderer: VectorImage.CurveRenderer }
+ }
+
+ Row {
+ Repeater {
+ model: renderers
+
+ VectorImage {
+ source: "../shared/svg/gradientxform.svg"
+ preferredRendererType: renderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/introCompat.qml b/tests/baseline/scenegraph/data/vectorimages/introCompat.qml
new file mode 100644
index 0000000000..1dce43a2d0
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/introCompat.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 600
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "intro-compat*.svg"]
+ }
+
+ VectorImage {
+ width: 600
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/jpegRequired.qml b/tests/baseline/scenegraph/data/vectorimages/jpegRequired.qml
new file mode 100644
index 0000000000..67b064c20f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/jpegRequired.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle {
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 3
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "jpeg-required*.svg"]
+ }
+
+ VectorImage {
+ width: 266
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/jpegRequiredCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/jpegRequiredCurveRenderer.qml
new file mode 100644
index 0000000000..3f7a2455e0
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/jpegRequiredCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle {
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 3
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "jpeg-required*.svg"]
+ }
+
+ VectorImage {
+ width: 266
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/paintColor.qml b/tests/baseline/scenegraph/data/vectorimages/paintColor.qml
new file mode 100644
index 0000000000..ad6aa3ac79
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/paintColor.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "paint-color*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/paintColorCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/paintColorCurveRenderer.qml
new file mode 100644
index 0000000000..8b7459d33f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/paintColorCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "paint-color*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/paintFill.qml b/tests/baseline/scenegraph/data/vectorimages/paintFill.qml
new file mode 100644
index 0000000000..06953d1ab6
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/paintFill.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "paint-fill*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/paintFillCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/paintFillCurveRenderer.qml
new file mode 100644
index 0000000000..26f3eb7f29
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/paintFillCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "paint-fill*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/paintGrad.qml b/tests/baseline/scenegraph/data/vectorimages/paintGrad.qml
new file mode 100644
index 0000000000..1b70160464
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/paintGrad.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 4
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "paint-grad*.svg"]
+ }
+
+ VectorImage {
+ width: 200
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/paintGradCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/paintGradCurveRenderer.qml
new file mode 100644
index 0000000000..70121f48e0
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/paintGradCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 4
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "paint-grad*.svg"]
+ }
+
+ VectorImage {
+ width: 200
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/paintStroke.qml b/tests/baseline/scenegraph/data/vectorimages/paintStroke.qml
new file mode 100644
index 0000000000..a34104809e
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/paintStroke.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 500
+
+ Grid {
+ columns: 4
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "paint-stroke*.svg"]
+ }
+
+ VectorImage {
+ width: 200
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/paintStrokeCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/paintStrokeCurveRenderer.qml
new file mode 100644
index 0000000000..bbf8f25b5c
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/paintStrokeCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 500
+
+ Grid {
+ columns: 4
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "paint-stroke*.svg"]
+ }
+
+ VectorImage {
+ width: 200
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/paintVfill.qml b/tests/baseline/scenegraph/data/vectorimages/paintVfill.qml
new file mode 100644
index 0000000000..bfc2077189
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/paintVfill.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "paint-vfill*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/paintVfillCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/paintVfillCurveRenderer.qml
new file mode 100644
index 0000000000..057558625d
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/paintVfillCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "paint-vfill*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/pathsData.qml b/tests/baseline/scenegraph/data/vectorimages/pathsData.qml
new file mode 100644
index 0000000000..6b277bc62f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/pathsData.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 4
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "paths-data*.svg"]
+ }
+
+ VectorImage {
+ width: 200
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/pathsDataCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/pathsDataCurveRenderer.qml
new file mode 100644
index 0000000000..2261e7d181
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/pathsDataCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 4
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "paths-data*.svg"]
+ }
+
+ VectorImage {
+ width: 200
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/renderElems.qml b/tests/baseline/scenegraph/data/vectorimages/renderElems.qml
new file mode 100644
index 0000000000..5ce8bab582
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/renderElems.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "render-elems*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/renderElemsCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/renderElemsCurveRenderer.qml
new file mode 100644
index 0000000000..747722848b
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/renderElemsCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "render-elems*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/renderGroups.qml b/tests/baseline/scenegraph/data/vectorimages/renderGroups.qml
new file mode 100644
index 0000000000..08edc30469
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/renderGroups.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "render-groups*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/renderGroupsCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/renderGroupsCurveRenderer.qml
new file mode 100644
index 0000000000..25ca7c5d07
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/renderGroupsCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "render-groups*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesCircle.qml b/tests/baseline/scenegraph/data/vectorimages/shapesCircle.qml
new file mode 100644
index 0000000000..40be30c78e
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesCircle.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-circle*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesCircleCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/shapesCircleCurveRenderer.qml
new file mode 100644
index 0000000000..8db2edd22a
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesCircleCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-circle*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesEllipse.qml b/tests/baseline/scenegraph/data/vectorimages/shapesEllipse.qml
new file mode 100644
index 0000000000..74a43349fa
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesEllipse.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-ellipse*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesEllipseCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/shapesEllipseCurveRenderer.qml
new file mode 100644
index 0000000000..7b6433ab7a
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesEllipseCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-ellipse*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesIntro.qml b/tests/baseline/scenegraph/data/vectorimages/shapesIntro.qml
new file mode 100644
index 0000000000..462d689c4c
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesIntro.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 300
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-intro*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesIntroCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/shapesIntroCurveRenderer.qml
new file mode 100644
index 0000000000..d48f042625
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesIntroCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 300
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-intro*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesLine.qml b/tests/baseline/scenegraph/data/vectorimages/shapesLine.qml
new file mode 100644
index 0000000000..35da140e9e
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesLine.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-line*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesLineCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/shapesLineCurveRenderer.qml
new file mode 100644
index 0000000000..36a0ac6b4b
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesLineCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-line*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesPolygon.qml b/tests/baseline/scenegraph/data/vectorimages/shapesPolygon.qml
new file mode 100644
index 0000000000..5ad1877c78
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesPolygon.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-polygon*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesPolygonCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/shapesPolygonCurveRenderer.qml
new file mode 100644
index 0000000000..147134915d
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesPolygonCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-polygon*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesPolyline.qml b/tests/baseline/scenegraph/data/vectorimages/shapesPolyline.qml
new file mode 100644
index 0000000000..53aa112ce3
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesPolyline.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-polyline*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesPolylineCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/shapesPolylineCurveRenderer.qml
new file mode 100644
index 0000000000..10989005be
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesPolylineCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-polyline*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesRect.qml b/tests/baseline/scenegraph/data/vectorimages/shapesRect.qml
new file mode 100644
index 0000000000..ff9c957461
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesRect.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-rect*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/shapesRectCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/shapesRectCurveRenderer.qml
new file mode 100644
index 0000000000..229fbe2080
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/shapesRectCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "shapes-rect*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structCommon.qml b/tests/baseline/scenegraph/data/vectorimages/structCommon.qml
new file mode 100644
index 0000000000..2f7cb2d125
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structCommon.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 300
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-common*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structCommonCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/structCommonCurveRenderer.qml
new file mode 100644
index 0000000000..57b40a8a52
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structCommonCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 300
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-common*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structCond.qml b/tests/baseline/scenegraph/data/vectorimages/structCond.qml
new file mode 100644
index 0000000000..f8f4e19986
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structCond.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 480
+
+ Grid {
+ columns: 3
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-cond*.svg"]
+ }
+
+ VectorImage {
+ width: 266
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structCondCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/structCondCurveRenderer.qml
new file mode 100644
index 0000000000..9d22493ef4
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structCondCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 480
+
+ Grid {
+ columns: 3
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-cond*.svg"]
+ }
+
+ VectorImage {
+ width: 266
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structDefs.qml b/tests/baseline/scenegraph/data/vectorimages/structDefs.qml
new file mode 100644
index 0000000000..9fe54d5886
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structDefs.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-defs*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structDefsCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/structDefsCurveRenderer.qml
new file mode 100644
index 0000000000..85b1b0a1f2
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structDefsCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-defs*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structDiscard.qml b/tests/baseline/scenegraph/data/vectorimages/structDiscard.qml
new file mode 100644
index 0000000000..725cc8a7a5
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structDiscard.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-discard*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structDiscardCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/structDiscardCurveRenderer.qml
new file mode 100644
index 0000000000..bbdbda6e15
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structDiscardCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-discard*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structFrag.qml b/tests/baseline/scenegraph/data/vectorimages/structFrag.qml
new file mode 100644
index 0000000000..cc2e809b49
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structFrag.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 480
+
+ Grid {
+ columns: 3
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-frag*.svg"]
+ }
+
+ VectorImage {
+ width: 266
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structFragCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/structFragCurveRenderer.qml
new file mode 100644
index 0000000000..89ad820dd0
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structFragCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 480
+
+ Grid {
+ columns: 3
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-frag*.svg"]
+ }
+
+ VectorImage {
+ width: 266
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structGroup.qml b/tests/baseline/scenegraph/data/vectorimages/structGroup.qml
new file mode 100644
index 0000000000..28bf0fa0e5
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structGroup.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-group*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structGroupCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/structGroupCurveRenderer.qml
new file mode 100644
index 0000000000..de358bcdfa
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structGroupCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 400
+ height: 600
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-group*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structSvg.qml b/tests/baseline/scenegraph/data/vectorimages/structSvg.qml
new file mode 100644
index 0000000000..923178bcdf
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structSvg.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-svg*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structSvgCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/structSvgCurveRenderer.qml
new file mode 100644
index 0000000000..66a4f19e38
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structSvgCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-svg*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structUse.qml b/tests/baseline/scenegraph/data/vectorimages/structUse.qml
new file mode 100644
index 0000000000..33f8bcbe9f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structUse.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 4
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-use*.svg"]
+ }
+
+ VectorImage {
+ width: 200
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/structUseCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/structUseCurveRenderer.qml
new file mode 100644
index 0000000000..820d8e8b8f
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/structUseCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 600
+
+ Grid {
+ columns: 4
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "struct-use*.svg"]
+ }
+
+ VectorImage {
+ width: 200
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/styling.qml b/tests/baseline/scenegraph/data/vectorimages/styling.qml
new file mode 100644
index 0000000000..c01a7fe4c7
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/styling.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 300
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "styling*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/stylingCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/stylingCurveRenderer.qml
new file mode 100644
index 0000000000..39f1162fc5
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/stylingCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 300
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "styling*.svg"]
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textAlign.qml b/tests/baseline/scenegraph/data/vectorimages/textAlign.qml
new file mode 100644
index 0000000000..13cec970e3
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textAlign.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "text-align*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textAlignCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/textAlignCurveRenderer.qml
new file mode 100644
index 0000000000..e9c23aabef
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textAlignCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "text-align*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textArea.qml b/tests/baseline/scenegraph/data/vectorimages/textArea.qml
new file mode 100644
index 0000000000..a2c8304877
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textArea.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 3
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "text-area*.svg"]
+ }
+
+ VectorImage {
+ width: 266
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textAreaCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/textAreaCurveRenderer.qml
new file mode 100644
index 0000000000..491d90b1ca
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textAreaCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 3
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "text-area*.svg"]
+ }
+
+ VectorImage {
+ width: 266
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textIntro.qml b/tests/baseline/scenegraph/data/vectorimages/textIntro.qml
new file mode 100644
index 0000000000..2c9d2cc813
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textIntro.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "text-intro*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textIntroCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/textIntroCurveRenderer.qml
new file mode 100644
index 0000000000..d667345f18
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textIntroCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "text-intro*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textOther.qml b/tests/baseline/scenegraph/data/vectorimages/textOther.qml
new file mode 100644
index 0000000000..f74c14c72a
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textOther.qml
@@ -0,0 +1,32 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 300
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: ListModel {
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/text-tselect-03-t.svg"
+ }
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/text-edit-201-t.svg"
+ }
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textOtherCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/textOtherCurveRenderer.qml
new file mode 100644
index 0000000000..9bf5ba219d
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textOtherCurveRenderer.qml
@@ -0,0 +1,32 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 300
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: ListModel {
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/text-tselect-03-t.svg"
+ }
+ ListElement {
+ fileUrl: "../shared/svg_12_testsuite/text-edit-201-t.svg"
+ }
+ }
+
+ VectorImage {
+ width: 400
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textStroke.qml b/tests/baseline/scenegraph/data/vectorimages/textStroke.qml
new file mode 100644
index 0000000000..3cf3be041e
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textStroke.qml
@@ -0,0 +1,6 @@
+import QtQuick
+import QtQuick.VectorImage
+
+VectorImage {
+ source: "../shared/svg/text_stroking.svg"
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textText.qml b/tests/baseline/scenegraph/data/vectorimages/textText.qml
new file mode 100644
index 0000000000..cd2a46f9af
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textText.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "text-text*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textTextCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/textTextCurveRenderer.qml
new file mode 100644
index 0000000000..7cab1ea4f1
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textTextCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 800
+ height: 800
+
+ Grid {
+ columns: 2
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "text-text*.svg"]
+ }
+
+ VectorImage {
+ width: 350
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textWs.qml b/tests/baseline/scenegraph/data/vectorimages/textWs.qml
new file mode 100644
index 0000000000..b67cf6060a
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textWs.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 500
+ height: 800
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "text-ws*.svg"]
+ }
+
+ VectorImage {
+ width: 500
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.GeometryRenderer
+ }
+ }
+ }
+}
diff --git a/tests/baseline/scenegraph/data/vectorimages/textWsCurveRenderer.qml b/tests/baseline/scenegraph/data/vectorimages/textWsCurveRenderer.qml
new file mode 100644
index 0000000000..1165d38fc6
--- /dev/null
+++ b/tests/baseline/scenegraph/data/vectorimages/textWsCurveRenderer.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.VectorImage
+import Qt.labs.folderlistmodel
+
+Rectangle{
+ id: topLevelItem
+ width: 500
+ height: 800
+
+ Grid {
+ columns: 1
+ anchors.fill: parent
+ Repeater {
+ model: FolderListModel {
+ folder: Qt.resolvedUrl("../shared/svg_12_testsuite/")
+ nameFilters: [ "text-ws*.svg"]
+ }
+
+ VectorImage {
+ width: 500
+ height: implicitHeight * width / implicitWidth
+ source: fileUrl
+ clip: true
+ preferredRendererType: VectorImage.CurveRenderer
+ }
+ }
+ }
+}
diff --git a/tests/manual/painterpathquickshape/ControlPanel.qml b/tests/manual/painterpathquickshape/ControlPanel.qml
index 87eb9ae3e7..ea3168d124 100644
--- a/tests/manual/painterpathquickshape/ControlPanel.qml
+++ b/tests/manual/painterpathquickshape/ControlPanel.qml
@@ -28,6 +28,7 @@ Item {
property alias painterComparisonAlpha: painterComparisonColorAlpha.value
property alias outlineEnabled: enableOutline.checked
property alias gradientType: gradientType.currentIndex
+ property alias fillScaleX: fillTransformSlider.value
property alias rendererName: rendererLabel.text
property alias preferCurve: rendererLabel.preferCurve
@@ -254,6 +255,19 @@ Item {
}
}
Label {
+ text: "Fill transform (scale x: " + fillTransformSlider.value.toFixed(2) + "):"
+ color: "white"
+ visible: gradientType.currentIndex != 0
+ }
+ Slider {
+ id: fillTransformSlider
+ Layout.fillWidth: true
+ from: 0.2
+ to: 5.0
+ value: 1.0
+ visible: gradientType.currentIndex != 0
+ }
+ Label {
text: "Fill alpha(" + Math.round(alphaSlider.value*100)/100 + "):"
color: "white"
}
diff --git a/tests/manual/painterpathquickshape/ControlledShape.qml b/tests/manual/painterpathquickshape/ControlledShape.qml
index e690f59ccc..26a57163cd 100644
--- a/tests/manual/painterpathquickshape/ControlledShape.qml
+++ b/tests/manual/painterpathquickshape/ControlledShape.qml
@@ -89,6 +89,7 @@ Item {
strokeStyle: controlPanel.outlineStyle
joinStyle: controlPanel.joinStyle
capStyle: controlPanel.capStyle
+ fillTransform: Qt.matrix4x4(controlPanel.fillScaleX,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1)
}
Repeater {
diff --git a/tests/manual/platforms/android/qml_in_android_service/.gitignore b/tests/manual/platforms/android/qml_in_android_service/.gitignore
new file mode 100644
index 0000000000..2300a2df35
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_android_service/.gitignore
@@ -0,0 +1,2 @@
+build/*
+CMakeLists.txt.user
diff --git a/tests/manual/platforms/android/qml_in_android_service/CMakeLists.txt b/tests/manual/platforms/android/qml_in_android_service/CMakeLists.txt
new file mode 100644
index 0000000000..47afd4c0c3
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_android_service/CMakeLists.txt
@@ -0,0 +1,33 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+cmake_minimum_required(VERSION 3.16)
+
+project(qml_in_android_service VERSION 0.1 LANGUAGES CXX)
+
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(Qt6 6.7 REQUIRED COMPONENTS Quick)
+
+qt_standard_project_setup(REQUIRES 6.6)
+
+
+qt_add_executable(qml_in_android_service
+ main.cpp
+)
+
+qt_add_qml_module(qml_in_android_service
+ URI qml_in_android_service
+ VERSION 1.0
+ QML_FILES Main.qml
+)
+
+target_link_libraries(qml_in_android_service
+ PRIVATE Qt6::Quick
+)
+
+install(TARGETS qml_in_android_service
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
diff --git a/tests/manual/platforms/android/qml_in_android_service/Main.qml b/tests/manual/platforms/android/qml_in_android_service/Main.qml
new file mode 100644
index 0000000000..6b8684e525
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_android_service/Main.qml
@@ -0,0 +1,100 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+import QtQuick
+import QtQuick.Controls
+
+Rectangle {
+ id: mainRectangle
+
+ property string colorStringFormat: "#1CB669"
+
+ signal onClicked()
+
+ color: colorStringFormat
+
+ Text {
+ id: helloText
+
+ text: "QML"
+ color: "white"
+ font.pixelSize: 72
+ font.bold: true
+ fontSizeMode: Text.VerticalFit
+ horizontalAlignment: Text.AlignHCenter
+
+ // Height is calculated based on display orientation
+ // from Screen height, dividing numbers are based on what what seem
+ // to look good on most displays
+ height: Screen.width > Screen.height ? Screen.height / 8 : (Screen.height / 2) / 8
+
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: parent.top
+ topMargin: 5
+ }
+ }
+
+
+ Text {
+ id: changeColorText
+
+ text: "Tap button to change Java view background color"
+ color: "white"
+ font.pixelSize: 58
+ fontSizeMode: Text.Fit
+ wrapMode: Text.Wrap
+ horizontalAlignment: Text.AlignHCenter
+
+ // Height and width are calculated based on display orientation
+ // from Screen height and width, dividing numbers are based on what seem to
+ // look good on most displays
+ height: Screen.width > Screen.height ? Screen.height / 8 : (Screen.height / 2) / 8
+ width: Screen.width > Screen.height ? (Screen.width / 2) / 2 : Screen.width / 2
+
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: helloText.bottom
+ topMargin: Screen.height / 10
+ }
+ }
+
+ Button {
+ id: button
+ // Width is calculated from changeColorText which is calculated from Screen size
+ // dividing numbers are base on what seems to look good on most displays
+ width: changeColorText.width / 1.6
+ height: changeColorText.height * 1.2
+
+ anchors {
+
+ horizontalCenter: parent.horizontalCenter
+ top: changeColorText.bottom
+ topMargin: height / 5
+ }
+
+ onClicked: mainRectangle.onClicked()
+
+ background: Rectangle {
+ id: buttonBackground
+
+ radius: 14
+ color: "#6200EE"
+ opacity: button.down ? 0.6 : 1
+ scale: button.down ? 0.9 : 1
+ }
+
+ contentItem: Text {
+ id: buttonText
+
+ text: "CHANGE COLOR"
+ color: "white"
+ font.pixelSize: 58
+ minimumPixelSize: 10
+ fontSizeMode: Text.Fit
+ font.bold: true
+ wrapMode: Text.Wrap
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+}
diff --git a/tests/manual/platforms/android/qml_in_android_service/main.cpp b/tests/manual/platforms/android/qml_in_android_service/main.cpp
new file mode 100644
index 0000000000..3293373061
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_android_service/main.cpp
@@ -0,0 +1,10 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+#include <QGuiApplication>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ return app.exec();
+}
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/.gitignore b/tests/manual/platforms/android/qml_in_java_based_android_project/.gitignore
new file mode 100644
index 0000000000..347e252ef1
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/.gitignore
@@ -0,0 +1,33 @@
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Log/OS Files
+*.log
+
+# Android Studio generated files and folders
+captures/
+.externalNativeBuild/
+.cxx/
+*.apk
+output.json
+
+# IntelliJ
+*.iml
+.idea/
+misc.xml
+deploymentTargetDropDown.xml
+render.experimental.xml
+
+# Keystore files
+*.jks
+*.keystore
+
+# Google Services (e.g. APIs or Firebase)
+google-services.json
+
+# Android Profiling
+*.hprof
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/README.md b/tests/manual/platforms/android/qml_in_java_based_android_project/README.md
new file mode 100644
index 0000000000..5199430bc8
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/README.md
@@ -0,0 +1,35 @@
+# What is this?
+
+This project is for manual testing of embedding QML into Android Services. It
+loads a QML view and a regular Android view side by side, both hosted by a
+Service, and wires them together.
+
+This application is meant to be built using Android Studio, with the Qt Gradle
+plugin. There is no need to manually build the Qt project or edit it, only this
+Android project.
+
+# How to sign the application
+In order to sign the application, you must have a keystore file and list it in
+a 'keystore.properties' file in the project root.
+
+1) Create 'keystore.properties' file in the same folder as this README
+2) Add the following information to the file:
+ ```
+ storePassword=somePassword
+ keyPassword=someOtherPassword
+ keyAlias=someKeyAlias
+ storeFile=/full/path/to/your/keystore.keystore
+ ```
+
+After this, the app build.gradle will read that file and extract the required
+information from it, and use that to sign the app before it is deployed.
+
+# How to configure QtBuild Gradle plugin
+The app-level build.gradle already includes and configures the plugin, but it requires some information about the environment it's running in: The Qt installation directory, and the Qt for Android kit directory.
+
+1) Create 'qtbuild.properties' file in the same folder as this README
+2) Add the following information to the file:
+ ```
+ qtKitDir=/path/to/your/android/kit/
+ qtPath=/path/to/your/Qt/installation // e.g. /etc/Qt/
+ ```
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/build.gradle b/tests/manual/platforms/android/qml_in_java_based_android_project/app/build.gradle
new file mode 100644
index 0000000000..3aa396c87a
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/build.gradle
@@ -0,0 +1,83 @@
+plugins {
+ id 'com.android.application'
+ id 'org.qtproject.qt.gradleplugin' version '0.1-SNAPSHOT+'
+}
+
+def qtBuildPropertiesFile = rootProject.file('qtbuild.properties');
+def qtBuildProperties = new Properties();
+qtBuildProperties.load(new FileInputStream(qtBuildPropertiesFile));
+QtBuild {
+ projectPath file('../../qml_in_android_service')
+ qtKitDir file(qtBuildProperties['qtKitDir'])
+ qtPath file(qtBuildProperties['qtPath'])
+}
+
+def keystorePropertiesFile = rootProject.file('keystore.properties');
+def keystoreProperties = new Properties();
+keystoreProperties.load(new FileInputStream(keystorePropertiesFile));
+
+android {
+ signingConfigs {
+ debug {
+ storeFile file(keystoreProperties['storeFile'])
+ storePassword keystoreProperties['storePassword']
+ keyAlias keystoreProperties['keyAlias']
+ keyPassword keystoreProperties['keyPassword']
+ }
+ }
+ namespace 'com.example.qml_in_java_based_android_project'
+ compileSdk 34
+
+ defaultConfig {
+ applicationId "com.example.qml_in_java_based_android_project"
+ minSdk 28
+ targetSdk 34
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ signingConfig signingConfigs.debug
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ signingConfig signingConfigs.debug
+ }
+ debug {
+ signingConfig signingConfigs.debug
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ packagingOptions {
+ jniLibs {
+ useLegacyPackaging true
+ }
+ }
+ sourceSets {
+ main {
+ assets {
+ srcDirs 'assets'
+ }
+ jniLibs {
+ srcDirs 'libs'
+ }
+ }
+ }
+}
+
+dependencies {
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'com.google.android.material:material:1.9.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ implementation "org.qtproject.qt.gradleplugin:QtGradlePlugin:0.1-SNAPSHOT"
+ implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.5'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
+}
+
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/AndroidManifest.xml b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..896b975a0b
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+
+ <application
+ android:allowBackup="true"
+ android:dataExtractionRules="@xml/data_extraction_rules"
+ android:fullBackupContent="@xml/backup_rules"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ tools:targetApi="34"
+ android:theme="@style/Theme.AppCompat">
+ <service
+ android:name=".QmlService"
+ android:enabled="true"
+ android:exported="true"/>
+
+ <activity
+ android:name=".MainActivity"
+ android:configChanges="orientation|screenLayout|screenSize"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java
new file mode 100644
index 0000000000..c619dce985
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/MainActivity.java
@@ -0,0 +1,20 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+package com.example.qml_in_java_based_android_project;
+
+import androidx.appcompat.app.AppCompatActivity;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class MainActivity extends AppCompatActivity
+{
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.view_main);
+ startService(new Intent(this, QmlService.class));
+ finish();
+ }
+}
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/QmlService.java b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/QmlService.java
new file mode 100644
index 0000000000..0c9de067e6
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/java/com/example/qml_in_java_based_android_project/QmlService.java
@@ -0,0 +1,204 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+package com.example.qml_in_java_based_android_project;
+
+import android.annotation.SuppressLint;
+import android.app.Service;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.util.Size;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.Gravity;
+
+import android.widget.Button;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import java.util.Random;
+import java.util.function.Consumer;
+
+import org.qtproject.qt.android.QtQuickView;
+import org.qtproject.qt.android.QtQmlStatus;
+import org.qtproject.qt.android.QtQmlStatusChangeListener;
+import org.qtproject.example.qml_in_android_service.Qml_in_android_service.Main;
+
+@SuppressLint("UseSwitchCompatOrMaterialCode")
+public class QmlService extends Service implements QtQmlStatusChangeListener
+{
+ private static final String TAG = "QmlService";
+ private WindowManager m_windowManager;
+ private QtQuickView m_serviceView;
+ private final Main m_serviceViewComponent = new Main();
+ private View m_mainView;
+
+ private TextView m_qmlBackgroundColorTextView;
+ private TextView m_qmlStatusTextView;
+ private View m_colorBox;
+ private Switch m_connectionSwitch;
+ private int m_qmlSignalListenerId;
+
+ @Override
+ public IBinder onBind(Intent intent)
+ {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+ @Override
+ public void onCreate()
+ {
+ m_windowManager = getSystemService(WindowManager.class);
+
+ getScreenSize((size) -> {
+ // Get the available geometry, and split it between the Android and QML UIs
+ m_serviceView = addQuickView(new Size(size.getWidth() / 2, size.getHeight()));
+ m_serviceViewComponent.setStatusChangeListener(this);
+ m_serviceView.loadComponent(m_serviceViewComponent);
+
+ m_mainView = addMainView(new Size(size.getWidth() / 2, size.getHeight()));
+ connectToNativeControls(m_mainView);
+ });
+ }
+
+ /*
+ Draw the "main" view on the left side of the screen, with the native controls
+ */
+ private View addMainView(final Size size)
+ {
+ final LayoutInflater inflater = getSystemService(LayoutInflater.class);
+
+ final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
+ size.getWidth(), size.getHeight(),
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ & ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ layoutParams.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
+
+ View mainView = inflater.inflate(R.layout.view_main, null);
+ m_windowManager.addView(mainView, layoutParams);
+ return mainView;
+ }
+
+ /*
+ Take size, and draw QtQuickView of that size on the right side of the screen
+ */
+ private QtQuickView addQuickView(final Size size)
+ {
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
+ size.getWidth(), size.getHeight(),
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ & ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ layoutParams.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
+
+ QtQuickView serviceView = new QtQuickView(this);
+ m_windowManager.addView(serviceView, layoutParams);
+ return serviceView;
+ }
+
+ /*
+ Draw empty View that fills the parent (screen in this case) to discover the available size,
+ report to consumer
+ */
+ private void getScreenSize(final Consumer<Size> screenSizeConsumer)
+ {
+ final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ & ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ final View view = new View(this) {
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom)
+ {
+ m_windowManager.removeView(this);
+ screenSizeConsumer.accept(new Size(right - left, bottom - top));
+ }
+ };
+ m_windowManager.addView(view, params);
+ }
+
+ @Override
+ public void onDestroy()
+ {
+ if (m_windowManager != null) {
+ if (m_serviceView != null) {
+ m_windowManager.removeView(m_serviceView);
+ m_serviceView = null;
+ }
+ if (m_mainView != null) {
+ m_windowManager.removeView(m_mainView);
+ m_mainView = null;
+ }
+ }
+ }
+
+ /*
+ Connect listeners to the native controls
+ */
+ private void connectToNativeControls(final View mainView)
+ {
+ m_qmlBackgroundColorTextView = mainView.findViewById(R.id.qmlBackgroundColorText);
+ m_qmlStatusTextView = mainView.findViewById(R.id.qmlStatus);
+ m_colorBox = mainView.findViewById(R.id.box);
+
+ m_connectionSwitch = mainView.findViewById(R.id.switch1);
+ m_connectionSwitch.setOnCheckedChangeListener(
+ (buttonView, isChecked) -> connectSwitchListener(isChecked));
+
+ final Button changeColorButton = mainView.findViewById(R.id.button);
+ changeColorButton.setOnClickListener(this::onChangeColorButtonListener);
+ }
+
+ public void onChangeColorButtonListener(View view)
+ {
+ m_serviceViewComponent.setColorStringFormat(getRandomColorString());
+
+ final String qmlColor = m_serviceView.getProperty("colorStringFormat");
+ m_qmlBackgroundColorTextView.setText(qmlColor);
+ m_colorBox.setBackgroundColor(Color.parseColor(qmlColor));
+ }
+
+ @Override
+ public void onStatusChanged(QtQmlStatus status)
+ {
+ m_qmlStatusTextView.setText(
+ String.format("%s %s", getResources().getString(R.string.qml_view_status), status));
+ // Once QML is loaded and the signal listener switch is not checked,
+ // connect to onClicked() signal in main.qml
+ if (status == QtQmlStatus.READY && m_connectionSwitch.isChecked())
+ connectSwitchListener(m_connectionSwitch.isChecked());
+ }
+
+ private void connectSwitchListener(boolean checked)
+ {
+ if (checked) {
+ m_qmlSignalListenerId = m_serviceView.connectSignalListener(
+ "onClicked", Object.class, this::onQmlChangeColorButtonClicked);
+ } else {
+ m_serviceView.disconnectSignalListener(m_qmlSignalListenerId);
+ }
+ }
+
+ public void onQmlChangeColorButtonClicked(String signal, Object o)
+ {
+ m_mainView.setBackgroundColor(Color.parseColor(getRandomColorString()));
+ }
+
+ private String getRandomColorString()
+ {
+ Random rand = new Random();
+ return String.format("#%06x", rand.nextInt(0xffffff + 1));
+ }
+}
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/layout/view_main.xml b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/layout/view_main.xml
new file mode 100644
index 0000000000..65b6b3fe6c
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/layout/view_main.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/mainLinear"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:baselineAligned="false"
+ android:background="#AF93DF">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="8dp"
+ android:gravity="center_horizontal"
+ android:includeFontPadding="false"
+ android:text="@string/java"
+ android:textColor="#FFFFFF"
+ android:textSize="24sp"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/qmlStatus"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="16dp"
+ android:gravity="center_horizontal"
+ android:text="@string/qml_view_status"
+ android:textColor="#FFFFFF"/>
+
+ <LinearLayout
+ android:id="@+id/buttonAndSwitchLayout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:orientation="horizontal"
+ android:layout_marginTop="16dp">
+
+ <LinearLayout
+ android:id="@+id/buttonLinearLayout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight="1">
+
+ <TextView
+ android:id="@+id/changeColorText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:maxLines="3"
+ android:text="@string/change_qml_background"
+ android:textColor="#FFFFFF" />
+
+ <Button
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="8dp"
+ android:text="@string/button"
+ android:textSize="14sp" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/switchLinearLayout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight="1">
+
+ <TextView
+ android:id="@+id/switchText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:maxLines="3"
+ android:text="@string/connect_qml_button_signal_listener"
+ android:textColor="#FFFFFF" />
+
+ <Switch
+ android:id="@+id/switch1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:textOff="@string/off"
+ android:textOn="@string/on"
+ android:showText="true"
+ android:checked="true"
+ tools:ignore="UseSwitchCompatOrMaterialXml" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/qmlColorLinear"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="10dp">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight="1">
+
+ <TextView
+ android:id="@+id/qmlViewBackgroundText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:maxLines="2"
+ android:text="@string/qml_view_background_color"
+ android:textColor="#FFFFFF" />
+
+ <TextView
+ android:id="@+id/qmlBackgroundColorText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:textColor="#FFFFFF" />
+ </LinearLayout>
+
+ <View
+ android:id="@+id/box"
+ android:layout_width="100dp"
+ android:layout_height="50dp"
+ android:layout_gravity="center_horizontal"
+ android:background="@android:color/transparent"
+ android:layout_weight="0"/>
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/values/strings.xml b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..39d33f40c9
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/values/strings.xml
@@ -0,0 +1,12 @@
+<resources>
+ <string name="app_name">qml_in_java_based_android_project</string>
+ <string name="button">Change color</string>
+ <string name="java">Java</string>
+ <string name="change_qml_background">Tap button to change QML view background color</string>
+ <string name="connect_qml_button_signal_listener">QML Button listener connected</string>
+ <string name="on">On</string>
+ <string name="off">Off</string>
+ <string name="qml_view_status">QML view status: </string>
+ <string name="qml_view_background_color">QML view background color:</string>
+</resources>
+
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/backup_rules.xml b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000000..04dd1acfe3
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Sample backup rules file; uncomment and customize as necessary.
+ See https://developer.android.com/guide/topics/data/autobackup
+ for details.
+ Note: This file is ignored for devices older that API 31
+ See https://developer.android.com/about/versions/12/backup-restore
+-->
+<full-backup-content>
+</full-backup-content>
+
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/data_extraction_rules.xml b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000000..9840b57766
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Sample data extraction rules file; uncomment and customize as necessary.
+ See https://developer.android.com/about/versions/12/backup-restore#xml-changes
+ for details.
+-->
+<data-extraction-rules>
+ <cloud-backup>
+ </cloud-backup>
+</data-extraction-rules>
+
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/build.gradle b/tests/manual/platforms/android/qml_in_java_based_android_project/build.gradle
new file mode 100644
index 0000000000..b92d690313
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/build.gradle
@@ -0,0 +1,4 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+id 'com.android.application' version '7.4.1' apply false
+}
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/gradle.properties b/tests/manual/platforms/android/qml_in_java_based_android_project/gradle.properties
new file mode 100644
index 0000000000..dacb776f4a
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/gradle.properties
@@ -0,0 +1,22 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
+
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/gradle/wrapper/gradle-wrapper.properties b/tests/manual/platforms/android/qml_in_java_based_android_project/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..62f495dfed
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/tests/manual/platforms/android/qml_in_java_based_android_project/settings.gradle b/tests/manual/platforms/android/qml_in_java_based_android_project/settings.gradle
new file mode 100644
index 0000000000..8a59ffb868
--- /dev/null
+++ b/tests/manual/platforms/android/qml_in_java_based_android_project/settings.gradle
@@ -0,0 +1,23 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ maven {
+ url "https://android.qt.io/maven/snapshots"
+ }
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ maven {
+ url "https://android.qt.io/maven/snapshots"
+ }
+ }
+}
+
+rootProject.name = "qml_in_java_based_android_project"
+include ':app'
diff --git a/tests/manual/quickcontrols/CMakeLists.txt b/tests/manual/quickcontrols/CMakeLists.txt
index e7f07e6110..fa3bf67e9d 100644
--- a/tests/manual/quickcontrols/CMakeLists.txt
+++ b/tests/manual/quickcontrols/CMakeLists.txt
@@ -10,6 +10,7 @@ if(LINUX)
endif()
add_subdirectory(headerview)
add_subdirectory(imagine/musicplayer)
+add_subdirectory(menus)
add_subdirectory(qquickdialog)
add_subdirectory(screenshots)
add_subdirectory(sidepanel)
diff --git a/tests/manual/quickcontrols/menus/CMakeLists.txt b/tests/manual/quickcontrols/menus/CMakeLists.txt
new file mode 100644
index 0000000000..ce757613a1
--- /dev/null
+++ b/tests/manual/quickcontrols/menus/CMakeLists.txt
@@ -0,0 +1,47 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(menus VERSION 0.1 LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+find_package(Qt6 REQUIRED COMPONENTS Quick QuickControls2)
+
+qt_standard_project_setup(REQUIRES 6.8)
+
+qt_add_executable(appmenus
+ main.cpp
+)
+
+qt_add_qml_module(appmenus
+ URI Menus
+ VERSION 1.0
+ QML_FILES
+ Main.qml
+ SOURCES
+ cppsettings.cpp
+ cppsettings.h
+ main.cpp
+ RESOURCES
+ icons/warning.png
+ icons/warning@2x.png
+)
+
+# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
+# If you are developing for iOS or macOS you should consider setting an
+# explicit, fixed bundle identifier manually though.
+set_target_properties(appmenus PROPERTIES
+# MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appmenus
+ MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
+ MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
+ MACOSX_BUNDLE TRUE
+ WIN32_EXECUTABLE TRUE
+)
+
+target_link_libraries(appmenus
+ PRIVATE
+ Qt6::Quick
+ Qt6::QuickControls2
+)
diff --git a/tests/manual/quickcontrols/menus/Main.qml b/tests/manual/quickcontrols/menus/Main.qml
new file mode 100644
index 0000000000..2c066381a9
--- /dev/null
+++ b/tests/manual/quickcontrols/menus/Main.qml
@@ -0,0 +1,472 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtCore
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import QtQuick.Dialogs
+
+ApplicationWindow {
+ id: window
+ width: 800
+ height: 600
+ visible: true
+ title: qsTr("Menus - style: %1").arg(currentStyle)
+
+ required property string currentStyle
+
+ Shortcut {
+ sequence: "Ctrl+Q"
+ onActivated: Qt.quit()
+ }
+
+ Settings {
+ id: settings
+
+ property alias windowX: window.x
+ property alias windowY: window.y
+ }
+
+ menuBar: MenuBar {
+ visible: menuBarVisibleSwitch.checked
+
+ Menu {
+ id: fileMenu
+ objectName: "file"
+ title: qsTr("&File")
+ popupType: popupTypeCombo.popupType()
+ ContextAction { text: qsTr("&New...") }
+ ContextMenuItem { text: "menuItem" }
+ ContextAction { text: qsTr("&Open...") }
+ ContextAction { text: qsTr("&Save") }
+ ContextAction { text: qsTr("Save &As...") }
+ Menu {
+ title: qsTr("Sub...")
+ ContextAction { text: qsTr("Sub action 1") }
+ ContextAction { text: qsTr("Sub action 2") }
+ Menu {
+ title: qsTr("SubSub...")
+ ContextAction { text: qsTr("SubSub action 1") }
+ ContextAction { text: qsTr("SubSub action 2") }
+ }
+ }
+ MenuSeparator { }
+ ContextAction {
+ text: qsTr("&Quit")
+ // This is needed for macOS since it takes priority over the Shortcut.
+ onTriggered: Qt.quit()
+ }
+ Action {
+ text: qsTr("Remove menu")
+ onTriggered: menuBar.removeMenu(fileMenu)
+ }
+ }
+ Menu {
+ id: editMenu
+ objectName: "edit"
+ title: qsTr("&Edit")
+ popupType: popupTypeCombo.popupType()
+ ContextAction {
+ id: cutAction
+ text: qsTr("Cut")
+ enabled: textArea.selectedText.length > 0
+ }
+ ContextAction {
+ text: qsTr("Copy")
+ enabled: textArea.selectedText.length > 0
+ }
+ ContextAction {
+ text: qsTr("Paste")
+ enabled: textArea.activeFocus
+ }
+
+ MenuSeparator {}
+
+ Action {
+ text: qsTr("Checkable menu")
+ checkable: true
+ checked: true
+ }
+ Action {
+ text: qsTr("Remove menu")
+ onTriggered: menuBar.removeMenu(editMenu)
+ }
+ Menu {
+ id: editSubMenu
+ title: qsTr("Find / Replace")
+ Action { text: qsTr("&Find") }
+ }
+
+ MenuSeparator {}
+
+ ContextAction {
+ text: qsTr("Dummy Action")
+ shortcut: "Ctrl+I"
+ }
+ }
+ MenuBarItem {
+ id: explicitMenuBarItem
+ menu: Menu {
+ id: menuBarItemMenu
+ objectName: "MenuBarItem"
+ title: "MenuBarItem"
+ popupType: popupTypeCombo.popupType()
+ ContextAction { text: qsTr("Action") }
+ Action {
+ text: qsTr("Remove menu")
+ onTriggered: menuBar.removeMenu(menuBarItemMenu)
+ }
+ }
+ }
+ }
+
+ Component {
+ id: extraMenuComp
+ Menu {
+ id: extraMenu
+ objectName: "Extra"
+ title: qsTr("&Extra")
+ ContextAction { text: qsTr("&Trigger") }
+ Action {
+ text: qsTr("Remove Extra menu")
+ onTriggered: menuBar.removeMenu(extraMenu)
+ }
+ }
+ }
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ Label {
+ text: qsTr("Right click on the window background to open a context menu. "
+ + "Right click on the TextArea to access its edit context menu.\n\n"
+ + "Things to check:\n\n"
+ + "- Do the menu items trigger their actions (check console for output)?\n"
+ + "- Do checkable menu items work?\n"
+ + "- Do the Edit menu items (in the MenuBar menu and edit context menu)"
+ + " work as expected with the TextArea?\n"
+ + " - Are they enabled/disabled as expected?\n"
+ + " - Does the TextArea keep focus after interacting with the Edit menu items?\n"
+ + "- Does adding and removing menu items work?\n"
+ + "- Do the menus in the MenuBar work?\n"
+ + "- Can you add and remove menus from the MenuBar?\n"
+ + "- Do shortcuts work?")
+ verticalAlignment: Text.AlignVCenter
+ wrapMode: Text.Wrap
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: window.width * 0.5
+ Layout.fillHeight: true
+ }
+
+ GroupBox {
+ title: qsTr("Context menu")
+
+ Layout.fillWidth: true
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ RowLayout {
+ Label {
+ text: qsTr("Popup type")
+ }
+
+ ComboBox {
+ id: popupTypeCombo
+ model: ["Item", "Window", "Native"]
+ onCurrentIndexChanged: CppSettings.popupType = currentIndex
+ currentIndex: CppSettings.popupType
+
+ function popupType() {
+ if (currentText === "Window")
+ return Popup.Window
+ else if (currentText === "Native")
+ return Popup.Native
+ else
+ return Popup.Item
+ }
+ }
+ }
+
+ Row {
+ Button {
+ text: qsTr("Add action")
+ onClicked: backgroundContextMenu.appendAction()
+ }
+ Button {
+ text: qsTr("Remove action")
+ onClicked: backgroundContextMenu.removeLastAction()
+ }
+
+ Button {
+ text: qsTr("Add sub-menu action")
+ onClicked: subMenu.appendAction()
+ }
+ Button {
+ text: qsTr("Remove sub-menu action")
+ onClicked: subMenu.removeLastAction()
+ }
+ }
+ }
+ }
+
+ TextArea {
+ id: textArea
+ text: qsTr("Dummy TextArea to test disabled menu items")
+
+ Layout.fillWidth: true
+ Layout.minimumHeight: 100
+
+ TapHandler {
+ objectName: "textAreaMouseTapHandler"
+ acceptedButtons: Qt.RightButton
+ onPressedChanged: if (pressed) editContextMenu.popup()
+ }
+ TapHandler {
+ objectName: "textAreaTouchTapHandler"
+ acceptedDevices: PointerDevice.TouchScreen
+ onLongPressed: editContextMenu.popup()
+ }
+ }
+
+ Component {
+ id: menuBarItemComp
+ MenuBarItem {
+ }
+ }
+
+ MessageDialog {
+ id: restartNeededDialog
+ buttons: MessageDialog.Ok
+ text: "Your current changes requires a restart to take effect!"
+ }
+
+ GroupBox {
+ title: qsTr("MenuBar")
+
+ Layout.fillWidth: true
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ Row {
+ Switch {
+ text: qsTr("Don't use native menu bar")
+ checked: CppSettings.dontUseNativeMenuBar
+
+ onClicked: {
+ CppSettings.dontUseNativeMenuBar = checked
+ restartNeededDialog.open()
+ }
+ }
+ Switch {
+ id: menuBarVisibleSwitch
+ text: qsTr("MenuBar visible")
+ checked: true
+ }
+ }
+ Row {
+ Button {
+ text: "Append menu"
+ onClicked: {
+ let menu = extraMenuComp.createObject(menuBar, { title: "Extra " + menuBar.count })
+ menuBar.addMenu(menu)
+ }
+ }
+ Button {
+ text: "Prepend menu"
+ onClicked: {
+ let menu = extraMenuComp.createObject(menuBar, { title: "Extra " + menuBar.count })
+ menuBar.insertMenu(0, menu)
+ }
+ }
+ Button {
+ text: qsTr("Add file menu")
+ onClicked: menuBar.addMenu(fileMenu)
+ }
+ Button {
+ text: "Change labels"
+ onClicked: {
+ fileMenu.title = "File changed"
+ cutAction.text = "Cut changed"
+ }
+ }
+ Button {
+ text: "toggle delegate"
+ onClicked: menuBar.delegate = menuBar.delegate ? null : menuBarItemComp
+ }
+ Switch {
+ text: "MenuBarItem visible"
+ checked: true
+ onCheckedChanged: explicitMenuBarItem.visible = checked
+ }
+ }
+ }
+ }
+ }
+
+ TapHandler {
+ objectName: "backgroundMouseTapHandler"
+ acceptedButtons: Qt.RightButton
+ onPressedChanged: if (pressed) backgroundContextMenu.popup()
+ }
+ TapHandler {
+ objectName: "backgroundTouchTapHandler"
+ acceptedDevices: PointerDevice.TouchScreen
+ onLongPressed: backgroundContextMenu.popup()
+ }
+
+ Component {
+ id: actionComponent
+
+ Action {}
+ }
+
+ component ContextAction: Action {
+ onCheckedChanged: (checked) => print("checked of \"" + text + "\" changed to " + checked)
+ onTriggered: print("triggered \"" + text + "\"")
+ }
+
+ component ContextMenuItem: MenuItem {
+ onCheckedChanged: print("checked of \"" + text + "\" changed to " + checked)
+ onTriggered: print("triggered \"" + text + "\"")
+ }
+
+ Menu {
+ id: backgroundContextMenu
+ objectName: "backgroundContextMenu"
+ popupType: popupTypeCombo.popupType()
+
+ function appendAction() {
+ let action = actionComponent.createObject(null, { text: qsTr("Extra context menu item") })
+ backgroundContextMenu.addAction(action)
+ }
+
+ function removeLastAction() {
+ // TODO: Can't use count here because it's 0: it uses contentModel->count(), but native menu items
+ // are not Qt Quick items, so we either need to document that you should use contentData.count
+ // or add an "actions" property. The problem with contentData is that it could contain
+ // non-Action objects. Another potential issue is that "It is not re-ordered when items are inserted or moved",
+ // making it unreliable as a general purpose container of actions if users add or remove them dynamically.
+ backgroundContextMenu.removeAction(backgroundContextMenu.actionAt(backgroundContextMenu.contentData.length - 1))
+ }
+
+ ContextAction {
+ text: qsTr("Context menu item")
+ shortcut: "A"
+ }
+ ContextMenuItem {
+ text: qsTr("Checkable context menu item")
+ checkable: true
+ }
+ ContextAction {
+ text: qsTr("Checked context menu item")
+ checkable: true
+ checked: true
+ shortcut: "C"
+ }
+ ContextAction {
+ text: qsTr("Disabled context menu item")
+ enabled: false
+ shortcut: "D"
+ }
+ ContextAction {
+ text: qsTr("Checked and disabled context menu item")
+ checkable: true
+ checked: true
+ enabled: false
+ shortcut: "E"
+ }
+
+ MenuSeparator {}
+
+ ContextAction {
+ text: qsTr("Context menu item with icon (name)")
+ icon.name: "mail-send"
+ }
+
+ ContextAction {
+ text: qsTr("Context menu item with icon (source)")
+ icon.source: "qrc:/qt/qml/Menus/icons/warning.png"
+ }
+
+ ContextAction {
+ text: qsTr("Context menu item with disabled icon (source)")
+ icon.source: "qrc:/qt/qml/Menus/icons/warning.png"
+ enabled: false
+ }
+
+ MenuSeparator {}
+
+ Menu {
+ id: subMenu
+ title: qsTr("Sub-menu")
+ objectName: title
+ popupType: popupTypeCombo.popupType()
+
+ function appendAction() {
+ let action = actionComponent.createObject(null, { text: qsTr("Extra sub-menu item") })
+ subMenu.addAction(action)
+ }
+
+ function removeLastAction() {
+ subMenu.removeAction(subMenu.actionAt(subMenu.contentData.length - 1))
+ }
+
+ ContextAction {
+ text: qsTr("Sub-menu item")
+ }
+ ContextAction {
+ text: qsTr("Checkable sub-menu item")
+ checkable: true
+ shortcut: "G"
+ }
+ ContextAction {
+ text: qsTr("Checked sub-menu item")
+ checkable: true
+ checked: true
+ }
+
+ MenuSeparator {}
+
+ ContextAction {
+ text: qsTr("Disabled sub-menu item")
+ enabled: false
+ shortcut: "I"
+ }
+ ContextAction {
+ text: qsTr("Checked and disabled sub-menu item")
+ checkable: true
+ checked: true
+ enabled: false
+ shortcut: "J"
+ }
+ Menu {
+ title: qsTr("SubSub...")
+ ContextAction { text: qsTr("SubSub action 1") }
+ ContextAction { text: qsTr("SubSub action 2") }
+ }
+ }
+ }
+
+ Menu {
+ id: editContextMenu
+ objectName: "editContextMenu"
+
+ ContextAction {
+ text: qsTr("Cut")
+ enabled: textArea.selectedText.length > 0
+ }
+ ContextAction {
+ text: qsTr("Copy")
+ enabled: textArea.selectedText.length > 0
+ }
+ ContextAction {
+ text: qsTr("Paste")
+ enabled: textArea.activeFocus
+ }
+ }
+}
+
diff --git a/tests/manual/quickcontrols/menus/Menu.qml b/tests/manual/quickcontrols/menus/Menu.qml
new file mode 100644
index 0000000000..0d18fca2ab
--- /dev/null
+++ b/tests/manual/quickcontrols/menus/Menu.qml
@@ -0,0 +1,6 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick.Controls
+
+Menu {}
diff --git a/tests/manual/quickcontrols/menus/cppsettings.cpp b/tests/manual/quickcontrols/menus/cppsettings.cpp
new file mode 100644
index 0000000000..589cea916b
--- /dev/null
+++ b/tests/manual/quickcontrols/menus/cppsettings.cpp
@@ -0,0 +1,43 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "cppsettings.h"
+
+#include <QCoreApplication>
+
+CppSettings::CppSettings(QObject *parent) :
+ QObject(parent),
+ mSettings("QtProject", "menus")
+{
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, dontUseNativeMenuBar());
+}
+
+bool CppSettings::dontUseNativeMenuBar() const
+{
+ return mSettings.value("dontUseNativeMenuBar").toBool();
+}
+
+void CppSettings::setDontUseNativeMenuBar(bool dontUseNativeMenuBar)
+{
+ const bool oldValue = this->dontUseNativeMenuBar();
+ if (dontUseNativeMenuBar == oldValue)
+ return;
+
+ QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, dontUseNativeMenuBar);
+ mSettings.setValue("dontUseNativeMenuBar", dontUseNativeMenuBar);
+ emit dontUseNativeMenuBarChanged();
+}
+
+int CppSettings::popupType() const
+{
+ return mSettings.value("popupType").toInt();
+}
+
+void CppSettings::setPopupType(int newPopupType)
+{
+ const int oldValue = popupType();
+ if (oldValue == newPopupType)
+ return;
+ mSettings.setValue("popupType", newPopupType);
+ emit popupTypeChanged();
+}
diff --git a/tests/manual/quickcontrols/menus/cppsettings.h b/tests/manual/quickcontrols/menus/cppsettings.h
new file mode 100644
index 0000000000..b6af1f9f09
--- /dev/null
+++ b/tests/manual/quickcontrols/menus/cppsettings.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef CPPSETTINGS_H
+#define CPPSETTINGS_H
+
+#include <QObject>
+#include <QQmlEngine>
+#include <QSettings>
+
+class CppSettings : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool dontUseNativeMenuBar READ dontUseNativeMenuBar WRITE setDontUseNativeMenuBar
+ NOTIFY dontUseNativeMenuBarChanged FINAL)
+ Q_PROPERTY(int popupType READ popupType WRITE setPopupType
+ NOTIFY popupTypeChanged FINAL)
+ QML_ELEMENT
+ QML_SINGLETON
+
+public:
+ explicit CppSettings(QObject *parent = nullptr);
+
+ bool dontUseNativeMenuBar() const;
+ void setDontUseNativeMenuBar(bool dontUseNativeMenuBar);
+
+ int popupType() const;
+ void setPopupType(int newPopupType);
+
+signals:
+ void dontUseNativeMenuBarChanged();
+ void popupTypeChanged();
+
+private:
+ QSettings mSettings;
+};
+
+#endif // CPPSETTINGS_H
diff --git a/tests/manual/quickcontrols/menus/icons/warning.png b/tests/manual/quickcontrols/menus/icons/warning.png
new file mode 100644
index 0000000000..590a61eb80
--- /dev/null
+++ b/tests/manual/quickcontrols/menus/icons/warning.png
Binary files differ
diff --git a/tests/manual/quickcontrols/menus/icons/warning@2x.png b/tests/manual/quickcontrols/menus/icons/warning@2x.png
new file mode 100644
index 0000000000..487fbafcfd
--- /dev/null
+++ b/tests/manual/quickcontrols/menus/icons/warning@2x.png
Binary files differ
diff --git a/tests/manual/quickcontrols/menus/main.cpp b/tests/manual/quickcontrols/menus/main.cpp
new file mode 100644
index 0000000000..e9b4e6d5eb
--- /dev/null
+++ b/tests/manual/quickcontrols/menus/main.cpp
@@ -0,0 +1,27 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QQuickStyle>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication::setOrganizationName("QtProject");
+ QGuiApplication::setApplicationName("menus");
+
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ engine.setInitialProperties({{ "currentStyle", QQuickStyle::name() }});
+ QObject::connect(
+ &engine,
+ &QQmlApplicationEngine::objectCreationFailed,
+ &app,
+ []() { QCoreApplication::exit(-1); },
+ Qt::QueuedConnection);
+ engine.loadFromModule("Menus", "Main");
+
+ return app.exec();
+}
+
diff --git a/tests/manual/quickcontrols/testbench/controls/Menu.qml b/tests/manual/quickcontrols/testbench/controls/Menu.qml
index df5bc55d20..f1948a7399 100644
--- a/tests/manual/quickcontrols/testbench/controls/Menu.qml
+++ b/tests/manual/quickcontrols/testbench/controls/Menu.qml
@@ -42,15 +42,18 @@ QtObject {
MenuItem {
text: "Checked"
+ checkable: true
checked: true
}
MenuItem {
text: "Checked + Pressed"
+ checkable: true
checked: true
down: true
}
MenuItem {
text: "Checked + Disabled"
+ checkable: true
checked: true
enabled: false
}
diff --git a/tests/manual/quickcontrols/testbench/controls/ToolBar.qml b/tests/manual/quickcontrols/testbench/controls/ToolBar.qml
index 2596f4309e..867556d152 100644
--- a/tests/manual/quickcontrols/testbench/controls/ToolBar.qml
+++ b/tests/manual/quickcontrols/testbench/controls/ToolBar.qml
@@ -34,6 +34,8 @@ QtObject {
ToolButton {
text: qsTr("ToolButton 3")
+ checkable: true
+ checked: true
}
}
}
diff --git a/tests/manual/quickcontrols/testbench/testbench.qml b/tests/manual/quickcontrols/testbench/testbench.qml
index 9c7f4a70aa..68975cfd69 100644
--- a/tests/manual/quickcontrols/testbench/testbench.qml
+++ b/tests/manual/quickcontrols/testbench/testbench.qml
@@ -139,7 +139,11 @@ Ui.ApplicationWindow {
text: "\ue801"
font.family: "fontello"
visible: searchTextField.length > 0
- onClicked: searchTextField.clear()
+ onClicked: {
+ searchTextField.clear()
+ // textEdited is not emitted for clear(), so we have to set this ourselves.
+ settings.lastSearchText = ""
+ }
Layout.leftMargin: -5
}
diff --git a/tests/manual/svg/data/styling/stroking_text.svg b/tests/manual/svg/data/styling/stroking_text.svg
new file mode 100644
index 0000000000..bacc04fff4
--- /dev/null
+++ b/tests/manual/svg/data/styling/stroking_text.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="250" height="200">
+ <text y="70" style="font-size: 80px; font-weight: bold; font-family: sans-serif; stroke-dasharray:5,5; fill: peachpuff; stroke: crimson; stroke-width:4.1px; stroke-linecap: square; stroke-linejoin: bevel;">pizazz</text>
+ <text y="150" style="font-size: 80px; font-weight: bold; font-family: sans-serif; fill: peachpuff; stroke: blue; stroke-width:4.1px; stroke-linecap: square; stroke-linejoin: bevel;">pizazz</text>
+</svg>
diff --git a/tests/manual/tableview/abstracttablemodel/main.qml b/tests/manual/tableview/abstracttablemodel/main.qml
index 5578e86dba..9c43af2f99 100644
--- a/tests/manual/tableview/abstracttablemodel/main.qml
+++ b/tests/manual/tableview/abstracttablemodel/main.qml
@@ -85,6 +85,22 @@ ApplicationWindow {
}
CheckBox {
+ id: movableColumnEnabled
+ checkable: true
+ checked: false
+ Layout.fillWidth: false
+ text: "Reorder columns"
+ }
+
+ CheckBox {
+ id: movableRowEnabled
+ checkable: true
+ checked: false
+ Layout.fillWidth: false
+ text: "Reorder rows"
+ }
+
+ CheckBox {
id: enableAnimation
checkable: true
checked: true
@@ -202,6 +218,14 @@ ApplicationWindow {
text: "Clear selection"
onClicked: tableView.selectionModel.clearSelection()
}
+ Button {
+ text: "Clear column reordering"
+ onClicked: tableView.clearColumnReordering()
+ }
+ Button {
+ text: "Clear row reordering"
+ onClicked: tableView.clearRowReordering()
+ }
}
}
@@ -450,7 +474,7 @@ ApplicationWindow {
}
}
- TableView {
+ HorizontalHeaderView {
id: topHeader
objectName: "topHeader"
anchors.left: centerScrollView.left
@@ -465,8 +489,11 @@ ApplicationWindow {
}
delegate: Rectangle {
+ required property bool containsDrag
implicitHeight: topHeader.height
implicitWidth: 20
+ border.width: containsDrag ? 1 : 0
+ border.color: containsDrag ? window.palette.text : window.palette.alternateBase
color: window.palette.alternateBase
Label {
anchors.centerIn: parent
@@ -481,10 +508,11 @@ ApplicationWindow {
syncView: tableView
syncDirection: Qt.Horizontal
+ movableColumns: movableColumnEnabled.checked
resizableColumns: resizableColumnsEnabled.checked
}
- TableView {
+ VerticalHeaderView {
id: leftHeader
objectName: "leftHeader"
anchors.left: menu.right
@@ -499,8 +527,11 @@ ApplicationWindow {
}
delegate: Rectangle {
+ required property bool containsDrag
implicitHeight: 50
implicitWidth: leftHeader.width
+ border.width: containsDrag ? 1 : 0
+ border.color: containsDrag ? window.palette.text : window.palette.alternateBase
color: window.palette.alternateBase
Label {
anchors.centerIn: parent
@@ -515,6 +546,7 @@ ApplicationWindow {
syncView: tableView
syncDirection: Qt.Vertical
+ movableRows: movableRowEnabled.checked
resizableRows: resizableRowsEnabled.checked
}
diff --git a/tests/manual/windowembedding/examples/clipping.qml b/tests/manual/windowembedding/examples/clipping.qml
index fa3d27db72..5e7778da37 100644
--- a/tests/manual/windowembedding/examples/clipping.qml
+++ b/tests/manual/windowembedding/examples/clipping.qml
@@ -16,17 +16,16 @@ Rectangle {
clip: true
- Window {
- id: redWindow
- flags: Qt.WindowTransparentForInput
- color: "lightgray"
- visible: true
+ WindowContainer {
width: 200; height: 200
- parent: flickable.contentItem
+ window: Window {
+ flags: Qt.WindowTransparentForInput
+ color: "lightgray"
- Image {
- source: "https://placedog.net/500/500?random"
- anchors.fill: parent
+ Image {
+ source: "https://placedog.net/500/500?random"
+ anchors.fill: parent
+ }
}
}
}
diff --git a/tests/manual/windowembedding/examples/stacking.qml b/tests/manual/windowembedding/examples/stacking.qml
index 7634bb0bff..38a84fa477 100644
--- a/tests/manual/windowembedding/examples/stacking.qml
+++ b/tests/manual/windowembedding/examples/stacking.qml
@@ -10,41 +10,41 @@ Rectangle {
property int windowZ: 0
- Window {
+ WindowContainer {
id: redWindow
- color: "red"
- visible: true
- parent: rootItem
+ window: Window {
+ color: "red"
- MouseArea {
- anchors.fill: parent
- onClicked: redWindow.z = ++rootItem.windowZ
+ MouseArea {
+ anchors.fill: parent
+ onClicked: redWindow.z = ++rootItem.windowZ
+ }
}
}
- Window {
+ WindowContainer {
id: greenWindow
- color: "green"
- visible: true
- parent: rootItem
x: 100; y: 100
+ window: Window {
+ color: "green"
- MouseArea {
- anchors.fill: parent
- onClicked: greenWindow.z = ++rootItem.windowZ
+ MouseArea {
+ anchors.fill: parent
+ onClicked: greenWindow.z = ++rootItem.windowZ
+ }
}
}
- Window {
+ WindowContainer {
id: blueWindow
- color: "blue"
- visible: true
- parent: rootItem
x: 200; y: 200
+ window: Window {
+ color: "blue"
- MouseArea {
- anchors.fill: parent
- onClicked: blueWindow.z = ++rootItem.windowZ
+ MouseArea {
+ anchors.fill: parent
+ onClicked: blueWindow.z = ++rootItem.windowZ
+ }
}
}
}
diff --git a/tests/manual/windowembedding/examples/transform.qml b/tests/manual/windowembedding/examples/transform.qml
index c07dae5850..932c52b0ab 100644
--- a/tests/manual/windowembedding/examples/transform.qml
+++ b/tests/manual/windowembedding/examples/transform.qml
@@ -19,22 +19,21 @@ Rectangle {
]
//scale: 3 // FIXME: Doesn't work when assigned like this
- Window {
- id: childWindow
- objectName: "childWindow"
- visible: true
- parent: rectangle
+ WindowContainer {
width: 200; height: 200
+ window: Window {
+ color: "lightgray"
- Image {
- source: "https://placedog.net/500/500?random"
- anchors.fill: parent
- }
+ Image {
+ source: "https://placedog.net/500/500?random"
+ anchors.fill: parent
+ }
- MouseArea {
- anchors.fill: parent
- onClicked: {
- rectangle.scale += 0.1
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ rectangle.scale += 0.1
+ }
}
}
}
diff --git a/tools/qmlaotstats/CMakeLists.txt b/tools/qmlaotstats/CMakeLists.txt
new file mode 100644
index 0000000000..1511f19e4b
--- /dev/null
+++ b/tools/qmlaotstats/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_get_tool_target_name(target_name qmlaotstats)
+qt_internal_add_tool(${target_name}
+ TARGET_DESCRIPTION "QML ahead-of-time compiler statistics aggregator"
+ TOOLS_TARGET Qml # special case
+ INSTALL_DIR "${INSTALL_LIBEXECDIR}"
+ SOURCES
+ main.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::QmlPrivate
+ Qt::QmlCompilerPrivate
+ Qt::QmlToolingSettingsPrivate
+)
+qt_internal_return_unless_building_tools()
diff --git a/tools/qmlaotstats/main.cpp b/tools/qmlaotstats/main.cpp
new file mode 100644
index 0000000000..24b34efec3
--- /dev/null
+++ b/tools/qmlaotstats/main.cpp
@@ -0,0 +1,83 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <QCommandLineParser>
+#include <QCoreApplication>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+#include <private/qqmljscompilerstats_p.h>
+#include <private/qqmljscompilerstatsreporter_p.h>
+
+using namespace Qt::Literals::StringLiterals;
+
+bool saveFormattedStats(const QString &stats, const QString &outputPath)
+{
+ QString directory = QFileInfo(outputPath).dir().path();
+ if (!QDir().mkpath(directory)) {
+ qDebug() << "Could not ensure the existence of" << directory;
+ return false;
+ }
+
+ QFile outputFile(outputPath);
+ if (!outputFile.open(QIODevice::Text | QIODevice::WriteOnly)) {
+ qDebug() << "Could not open file" << outputPath;
+ return false;
+ }
+
+ if (outputFile.write(stats.toLatin1()) == -1) {
+ qDebug() << "Could not write formatted AOT stats to" << outputPath;
+ return false;
+ } else {
+ qDebug() << "Formatted AOT stats saved to" << outputPath;
+ }
+
+ return true;
+}
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
+
+ QCommandLineParser parser;
+ parser.addHelpOption();
+ parser.setApplicationDescription("Internal development tool.");
+ parser.addPositionalArgument("mode", "Choose whether to aggregate or display aotstats files",
+ "[aggregate|format]");
+ parser.addPositionalArgument("input", "Aggregate mode: the aotstatslist file to aggregate. "
+ "Format mode: the aotstats file to display.");
+ parser.addPositionalArgument("output", "Aggregate mode: the path where to store the "
+ "aggregated aotstats. Format mode: the the path where "
+ "the formatted output will be saved.");
+ parser.process(app);
+
+ const auto &positionalArgs = parser.positionalArguments();
+ if (positionalArgs.size() != 3) {
+ qDebug().noquote() << parser.helpText();
+ return EXIT_FAILURE;
+ }
+
+ const auto &mode = positionalArgs.first();
+ if (mode == u"aggregate"_s) {
+ const auto aggregated = QQmlJS::AotStats::aggregateAotstatsList(positionalArgs[1]);
+ if (!aggregated.has_value())
+ return EXIT_FAILURE;
+ if (!aggregated->saveToDisk(positionalArgs[2]))
+ return EXIT_FAILURE;
+
+ } else if (mode == u"format"_s) {
+ const auto aotstats = QQmlJS::AotStats::parseAotstatsFile(positionalArgs[1]);
+ if (!aotstats.has_value())
+ return EXIT_FAILURE;
+ const QQmlJS::AotStatsReporter reporter(aotstats.value());
+ if (!saveFormattedStats(reporter.format(), positionalArgs[2]))
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index 1180931d9f..37a2298717 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -15,11 +15,12 @@
#include <QLoggingCategory>
#include <private/qqmlirbuilder_p.h>
-#include <private/qqmljsparser_p.h>
+#include <private/qqmljscompiler_p.h>
#include <private/qqmljslexer_p.h>
-#include <private/qqmljsresourcefilemapper_p.h>
#include <private/qqmljsloadergenerator_p.h>
-#include <private/qqmljscompiler_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsresourcefilemapper_p.h>
+#include <private/qqmljsutils_p.h>
#include <private/qresourcerelocater_p.h>
#include <algorithm>
@@ -100,6 +101,11 @@ int main(int argc, char **argv)
QCommandLineOption validateBasicBlocksOption("validate-basic-blocks"_L1, QCoreApplication::translate("main", "Performs checks on the basic blocks of a function compiled ahead of time to validate its structure and coherence"));
parser.addOption(validateBasicBlocksOption);
+ QCommandLineOption dumpAotStatsOption("dump-aot-stats"_L1, QCoreApplication::translate("main", "Dumps statistics about ahead-of-time compilation of bindings and functions"));
+ parser.addOption(dumpAotStatsOption);
+ QCommandLineOption moduleIdOption("module-id"_L1, QCoreApplication::translate("main", "Identifies the module of the qml file being compiled for aot stats"), QCoreApplication::translate("main", "id"));
+ parser.addOption(moduleIdOption);
+
QCommandLineOption outputFileOption("o"_L1, QCoreApplication::translate("main", "Output file name"), QCoreApplication::translate("main", "file name"));
parser.addOption(outputFileOption);
@@ -134,6 +140,11 @@ int main(int argc, char **argv)
if (target == GenerateLoader && parser.isSet(resourceNameOption))
target = GenerateLoaderStandAlone;
+ if (parser.isSet(dumpAotStatsOption) && !parser.isSet(moduleIdOption)) {
+ fprintf(stderr, "--dump-aot-stats set without setting --module-id");
+ return EXIT_FAILURE;
+ }
+
const QStringList sources = parser.positionalArguments();
if (sources.isEmpty()){
parser.showHelp();
@@ -257,7 +268,13 @@ int main(int argc, char **argv)
logger.setSilent(true);
QQmlJSAotCompiler cppCodeGen(
- &importer, u':' + inputResourcePath, parser.values(importsOption), &logger);
+ &importer, u':' + inputResourcePath,
+ QQmlJSUtils::cleanPaths(parser.values(importsOption)), &logger);
+
+ if (parser.isSet(dumpAotStatsOption)) {
+ QQmlJS::QQmlJSAotCompilerStats::setRecordAotStats(true);
+ QQmlJS::QQmlJSAotCompilerStats::setModuleId(parser.value(moduleIdOption));
+ }
if (parser.isSet(validateBasicBlocksOption))
cppCodeGen.m_flags.setFlag(QQmlJSAotCompiler::ValidateBasicBlocks);
@@ -277,6 +294,9 @@ int main(int argc, char **argv)
if (parser.isSet(warningsAreErrorsOption))
return EXIT_FAILURE;
}
+
+ if (parser.isSet(dumpAotStatsOption))
+ QQmlJS::QQmlJSAotCompilerStats::instance()->saveToDisk(outputFileName + u".aotstats"_s);
}
} else if (inputFile.endsWith(".js"_L1) || inputFile.endsWith(".mjs"_L1)) {
QQmlJSCompileError error;
diff --git a/tools/qmllint/main.cpp b/tools/qmllint/main.cpp
index 05dc667232..da0f21acb5 100644
--- a/tools/qmllint/main.cpp
+++ b/tools/qmllint/main.cpp
@@ -4,10 +4,11 @@
#include <QtQmlToolingSettings/private/qqmltoolingsettings_p.h>
#include <QtQmlToolingSettings/private/qqmltoolingutils_p.h>
-#include <QtQmlCompiler/private/qqmljsresourcefilemapper_p.h>
#include <QtQmlCompiler/private/qqmljscompiler_p.h>
#include <QtQmlCompiler/private/qqmljslinter_p.h>
#include <QtQmlCompiler/private/qqmljsloggingutils_p.h>
+#include <QtQmlCompiler/private/qqmljsresourcefilemapper_p.h>
+#include <QtQmlCompiler/private/qqmljsutils_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/qfile.h>
@@ -186,6 +187,18 @@ All warnings can be set to three levels:
QLatin1String("directory"));
parser.addOption(pluginPathsOption);
+ QCommandLineOption maxWarnings(
+ QStringList() << "W"
+ << "max-warnings",
+ QLatin1String("Exit with an error code if more than \"count\" many"
+ "warnings are found by qmllint. By default or if \"count\" "
+ "is -1, warnings do not cause qmllint "
+ "to return with an error exit code."),
+ "count"
+ );
+ parser.addOption(maxWarnings);
+ settings.addOption("MaxWarnings", -1);
+
auto levelToString = [](const QQmlJS::LoggerCategory &category) -> QString {
Q_ASSERT(category.isIgnored() || category.level() != QtCriticalMsg);
if (category.isIgnored())
@@ -301,7 +314,7 @@ All warnings can be set to three levels:
QStringList defaultQmldirFiles;
if (parser.isSet(qmldirFilesOption)) {
- defaultQmldirFiles = parser.values(qmldirFilesOption);
+ defaultQmldirFiles = QQmlJSUtils::cleanPaths(parser.values(qmldirFilesOption));
} else if (!parser.isSet(qmlImportNoDefault)){
// If nothing given explicitly, use the qmldir file from the current directory.
QFileInfo qmldirFile(QStringLiteral("qmldir"));
@@ -462,7 +475,13 @@ All warnings can be set to three levels:
useJson ? &jsonFiles : nullptr, qmlImportPaths,
qmldirFiles, resourceFiles, categories);
}
- success &= (lintResult == QQmlJSLinter::LintSuccess);
+ success &= (lintResult == QQmlJSLinter::LintSuccess || lintResult == QQmlJSLinter::HasWarnings);
+ if (success && parser.isSet(maxWarnings))
+ {
+ int value = parser.value(maxWarnings).toInt();
+ if (value != -1 && value < linter.logger()->warnings().size())
+ success = false;
+ }
if (isFixing) {
if (lintResult != QQmlJSLinter::LintSuccess && lintResult != QQmlJSLinter::HasWarnings)
diff --git a/tools/qmlls/qmllanguageservertool.cpp b/tools/qmlls/qmllanguageservertool.cpp
index 34138638b7..aa69b058bc 100644
--- a/tools/qmlls/qmllanguageservertool.cpp
+++ b/tools/qmlls/qmllanguageservertool.cpp
@@ -50,47 +50,83 @@ class StdinReader : public QObject
{
Q_OBJECT
public:
- void run()
- {
- auto guard = qScopeGuard([this]() { emit eof(); });
- const constexpr qsizetype bufSize = 1024;
- qsizetype bytesInBuf = 0;
- char bufferData[2 * bufSize];
- char *buffer = static_cast<char *>(bufferData);
-
- auto trySend = [this, &bytesInBuf, buffer]() {
- if (bytesInBuf == 0)
- return;
- qsizetype toSend = bytesInBuf;
- bytesInBuf = 0;
- QByteArray dataToSend(buffer, toSend);
- emit receivedData(dataToSend);
- };
- QHttpMessageStreamParser streamParser(
+ StdinReader()
+ : m_streamReader(
[](const QByteArray &, const QByteArray &) { /* just a header, do nothing */ },
- [&trySend](const QByteArray &) {
+ [this](const QByteArray &) {
+ // stop reading until we are sure that the server is not shutting down
+ m_isReading = false;
+
// message body
- trySend();
+ m_shouldSendData = true;
},
- [&trySend](QtMsgType, QString) {
+ [this](QtMsgType, QString) {
// there was an error
- trySend();
+ m_shouldSendData = true;
},
- QHttpMessageStreamParser::UNBUFFERED);
-
- while (std::cin.get(buffer[bytesInBuf])) { // should poll/select and process events
- qsizetype readNow = std::cin.readsome(buffer + bytesInBuf + 1, bufSize) + 1;
- QByteArray toAdd(buffer + bytesInBuf, readNow);
- bytesInBuf += readNow;
- if (bytesInBuf >= bufSize)
- trySend();
- streamParser.receiveData(toAdd);
- }
- trySend();
+ QHttpMessageStreamParser::UNBUFFERED)
+ {
+ }
+
+ void sendData()
+ {
+ const bool isEndOfMessage = !m_isReading && !m_hasEof;
+ const qsizetype toSend = m_bytesInBuf;
+ m_bytesInBuf = 0;
+ const QByteArray dataToSend(m_buffer, toSend);
+ emit receivedData(dataToSend, isEndOfMessage);
}
+
+private:
+ const static constexpr qsizetype s_bufSize = 1024;
+ qsizetype m_bytesInBuf = 0;
+ char m_buffer[2 * s_bufSize] = {};
+ QHttpMessageStreamParser m_streamReader;
+ /*!
+ \internal
+ Indicates if the current message is not read out entirely.
+ */
+ bool m_isReading = true;
+ /*!
+ \internal
+ Indicates if an EOF was encountered. No more data can be read after an EOF.
+ */
+ bool m_hasEof = false;
+ /*!
+ \internal
+ Indicates whether sendData() should be called or not.
+ */
+ bool m_shouldSendData = false;
signals:
- void receivedData(const QByteArray &data);
+ void receivedData(const QByteArray &data, bool canRequestMoreData);
void eof();
+public slots:
+ void readNextMessage()
+ {
+ if (m_hasEof)
+ return;
+ m_isReading = true;
+ // Try to fill up the buffer as much as possible before calling the queued signal:
+ // each loop iteration might read only one character from std::in in the worstcase, this
+ // happens for example on macos.
+ while (m_isReading) {
+ // block while waiting for some data
+ if (!std::cin.get(m_buffer[m_bytesInBuf])) {
+ m_hasEof = true;
+ emit eof();
+ return;
+ }
+ // see if more data is available and fill the buffer with it
+ qsizetype readNow = std::cin.readsome(m_buffer + m_bytesInBuf + 1, s_bufSize) + 1;
+ QByteArray toAdd(m_buffer + m_bytesInBuf, readNow);
+ m_bytesInBuf += readNow;
+ m_streamReader.receiveData(std::move(toAdd));
+
+ m_shouldSendData |= m_bytesInBuf >= s_bufSize;
+ if (std::exchange(m_shouldSendData, false))
+ sendData();
+ }
+ }
};
// To debug:
@@ -193,6 +229,11 @@ int main(int argv, char *argc[])
parser.addOption(noCMakeCallsOption);
settings.addOption("no-cmake-calls", "false");
+ QCommandLineOption docDir(QStringList() << "p",
+ QLatin1String("Documentation path to use for the documentation hints feature"));
+ parser.addOption(docDir);
+ settings.addOption("docDir");
+
parser.process(app);
if (parser.isSet(writeDefaultsOption)) {
@@ -231,6 +272,9 @@ int main(int argv, char *argc[])
},
(parser.isSet(ignoreSettings) ? nullptr : &settings));
+ if (parser.isSet(docDir))
+ qmlServer.codeModel()->setDocumentationRootPath(parser.value(docDir).toUtf8());
+
const bool disableCMakeCallsViaEnvironment =
qmlGetConfigOption<bool, qmlConvertBoolConfigOption>("QMLLS_NO_CMAKE_CALLS");
@@ -299,16 +343,28 @@ int main(int argv, char *argc[])
qmlServer.codeModel()->setImportPaths(importPaths);
StdinReader r;
+ QThread workerThread;
+ r.moveToThread(&workerThread);
QObject::connect(&r, &StdinReader::receivedData,
qmlServer.server(), &QLanguageServer::receiveData);
- QObject::connect(&r, &StdinReader::eof, &app, [&app]() {
+ QObject::connect(qmlServer.server(), &QLanguageServer::readNextMessage, &r,
+ &StdinReader::readNextMessage);
+ auto exit = [&app, &workerThread]() {
+ workerThread.quit();
+ workerThread.wait();
QTimer::singleShot(100, &app, []() {
QCoreApplication::processEvents();
QCoreApplication::exit();
});
- });
- QThreadPool::globalInstance()->start([&r]() { r.run(); });
+ };
+ QObject::connect(&r, &StdinReader::eof, &app, exit);
+ QObject::connect(qmlServer.server(), &QLanguageServer::shutdown, exit);
+
+ emit r.readNextMessage();
+ workerThread.start();
app.exec();
+ workerThread.quit();
+ workerThread.wait();
return qmlServer.returnValue();
}
diff --git a/tools/qmltc/main.cpp b/tools/qmltc/main.cpp
index a310c3d3c6..1899f4087e 100644
--- a/tools/qmltc/main.cpp
+++ b/tools/qmltc/main.cpp
@@ -9,6 +9,7 @@
#include <private/qqmljscompiler_p.h>
#include <private/qqmljsresourcefilemapper_p.h>
+#include <private/qqmljsutils_p.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qurl.h>
@@ -174,7 +175,7 @@ int main(int argc, char **argv)
if (!parser.isSet(bareOption))
importPaths.append(QLibraryInfo::path(QLibraryInfo::QmlImportsPath));
- QStringList qmldirFiles = parser.values(qmldirOption);
+ QStringList qmldirFiles = QQmlJSUtils::cleanPaths(parser.values(qmldirOption));
QString outputCppFile;
if (!parser.isSet(outputCppOption)) {
diff --git a/tools/qmltc/qmltccompiler.cpp b/tools/qmltc/qmltccompiler.cpp
index 75bd580e07..b3d15ab68f 100644
--- a/tools/qmltc/qmltccompiler.cpp
+++ b/tools/qmltc/qmltccompiler.cpp
@@ -707,24 +707,10 @@ compileMethodParameters(const QList<QQmlJSMetaParameter> &parameterInfos, bool a
return parameters;
}
-static QString figureReturnType(const QQmlJSMetaMethod &m)
-{
- const bool isVoidMethod =
- m.returnTypeName() == u"void" || m.methodType() == QQmlJSMetaMethodType::Signal;
- Q_ASSERT(isVoidMethod || m.returnType());
- QString type;
- if (isVoidMethod) {
- type = u"void"_s;
- } else {
- type = m.returnType()->augmentedInternalName();
- }
- return type;
-}
-
void QmltcCompiler::compileMethod(QmltcType &current, const QQmlJSMetaMethod &m,
const QQmlJSScope::ConstPtr &owner)
{
- const auto returnType = figureReturnType(m);
+ const QString returnType = m.returnType()->augmentedInternalName();
const QList<QmltcVariable> compiledParams = compileMethodParameters(m.parameters());
const auto methodType = m.methodType();
@@ -1926,7 +1912,7 @@ void QmltcCompiler::compileScriptBinding(QmltcType &current,
const QString signalName = signal.methodName();
const QString slotName = newSymbol(signalName + u"_slot");
- const QString signalReturnType = figureReturnType(signal);
+ const QString signalReturnType = signal.returnType()->augmentedInternalName();
const QList<QmltcVariable> slotParameters =
compileMethodParameters(signal.parameters(), /* allow unnamed = */ true);
diff --git a/tools/qmltc/qmltctyperesolver.cpp b/tools/qmltc/qmltctyperesolver.cpp
index a7bf9debac..9c53686736 100644
--- a/tools/qmltc/qmltctyperesolver.cpp
+++ b/tools/qmltc/qmltctyperesolver.cpp
@@ -12,7 +12,7 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qdiriterator.h>
-Q_LOGGING_CATEGORY(lcTypeResolver2, "qml.qmltc.typeresolver", QtInfoMsg);
+Q_STATIC_LOGGING_CATEGORY(lcTypeResolver2, "qml.qmltc.typeresolver", QtInfoMsg);
void QmltcTypeResolver::init(QmltcVisitor *visitor, QQmlJS::AST::Node *program)
{
diff --git a/tools/qmltc/qmltcvisitor.cpp b/tools/qmltc/qmltcvisitor.cpp
index 119308ef65..a6ec1f8661 100644
--- a/tools/qmltc/qmltcvisitor.cpp
+++ b/tools/qmltc/qmltcvisitor.cpp
@@ -690,6 +690,7 @@ void QmltcVisitor::checkNamesAndTypes(const QQmlJSScope::ConstPtr &type)
u"const_cast"_s,
u"consteval"_s,
u"constexpr"_s,
+ u"constinit"_s,
u"continue"_s,
u"decltype"_s,
u"default"_s,
diff --git a/tools/qmltyperegistrar/qmltyperegistrar.cpp b/tools/qmltyperegistrar/qmltyperegistrar.cpp
index 248926fb33..937c8a356f 100644
--- a/tools/qmltyperegistrar/qmltyperegistrar.cpp
+++ b/tools/qmltyperegistrar/qmltyperegistrar.cpp
@@ -198,6 +198,7 @@ int main(int argc, char **argv)
return EXIT_SUCCESS;
typeRegistrar.setReferencedTypes(processor.referencedTypes());
+ typeRegistrar.setUsingDeclarations(processor.usingDeclarations());
const QString qmltypes = parser.value(pluginTypesOption);
if (!typeRegistrar.generatePluginTypes(qmltypes)) {
error(qmltypes) << "Cannot generate qmltypes file";
diff --git a/tools/svgtoqml/main.cpp b/tools/svgtoqml/main.cpp
index 64474030dc..51c2f741ca 100644
--- a/tools/svgtoqml/main.cpp
+++ b/tools/svgtoqml/main.cpp
@@ -25,7 +25,7 @@ int main(int argc, char *argv[])
parser.setApplicationDescription("SVG to QML converter [tech preview]");
parser.addHelpOption();
parser.addPositionalArgument("input", QCoreApplication::translate("main", "SVG file to read."));
- parser.addPositionalArgument("output", QCoreApplication::translate("main", "QML file to write."));
+ parser.addPositionalArgument("output", QCoreApplication::translate("main", "QML file to write."), "[output]");
QCommandLineOption optimizeOption("optimize-paths",
QCoreApplication::translate("main", "Optimize paths for the curve renderer."));
@@ -74,7 +74,8 @@ int main(int argc, char *argv[])
#ifdef ENABLE_GUI
QCommandLineOption guiOption(QStringList() << "v" << "view",
- QCoreApplication::translate("main", "Display the SVG in a window."));
+ QCoreApplication::translate("main", "Display the generated QML in a window. This is the default behavior if no "
+ "output file is specified."));
parser.addOption(guiOption);
#endif
parser.process(app);
@@ -114,10 +115,10 @@ int main(int argc, char *argv[])
generator.setAssetFileDirectory(assetOutputDirectory);
generator.setAssetFilePrefix(assetOutputPrefix);
generator.setRetainFilePaths(keepPaths);
- generator.generate();
+ bool ok = generator.generate();
#ifdef ENABLE_GUI
- if (parser.isSet(guiOption)) {
+ if (ok && (parser.isSet(guiOption) || outFileName.isEmpty())) {
app.setOrganizationName("QtProject");
const QUrl url(QStringLiteral("qrc:/main.qml"));
QQmlApplicationEngine engine;
@@ -134,8 +135,7 @@ int main(int argc, char *argv[])
engine.load(url);
return app.exec();
}
-#else
- return 0;
#endif
+ return ok ? 0 : 1;
}